home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 10 Tools / 10-Tools.zip / cproto.zip / cproto46 / trace.c < prev    next >
C/C++ Source or Header  |  1998-01-18  |  6KB  |  319 lines

  1. /* $Id: trace.c,v 4.2 1998/01/19 00:49:33 cthuang Exp $
  2.  *
  3.  * Simple malloc debugging (for finding leaks)
  4.  *
  5.  * This is a cut-down version of a module I wrote originally for 'vile', it
  6.  * requires an ANSI compiler.  Its main purpose is to allow tracing problems in
  7.  * a repeatable test, including malloc/free bugs -- dickey@clark.net
  8.  */
  9. #if HAVE_CONFIG_H
  10. #include <config.h>
  11. #endif
  12.  
  13. #include <trace.h>    /* interface of this module */
  14.  
  15. #include <stdlib.h>
  16. #include <stdio.h>
  17.  
  18. #if TIME_WITH_SYS_TIME
  19. # include <sys/time.h>
  20. # include <time.h>
  21. #else
  22. # if HAVE_SYS_TIME_H
  23. #  include <sys/time.h>
  24. # else
  25. #  include <time.h>
  26. # endif
  27. #endif
  28.  
  29. #define    BEFORE    0    /* padding "before" allocated area */
  30. #define AFTER   0    /* padding "after" allocated area */
  31.  
  32. #include <stdarg.h>
  33.  
  34. #if    DOALLOC
  35. #undef    malloc
  36. #undef    realloc
  37. #undef    free
  38. #endif    /* DOALLOC */
  39.  
  40. void
  41. Trace(char *format, ...)
  42. {
  43.     static    FILE    *fp;
  44.     va_list ap;
  45.  
  46.     if (!fp)
  47.         fp = fopen("Trace.out", "w");
  48.     if (!fp)
  49.         abort();
  50.  
  51.     va_start(ap,format);
  52.     if (format != 0) {
  53.         vfprintf(fp, format, ap);
  54.         va_end(ap);
  55.         (void)fflush(fp);
  56.     } else {
  57.         (void)fclose(fp);
  58.         (void)fflush(stdout);
  59.         (void)fflush(stderr);
  60.     }
  61. }
  62.  
  63. #define    SECS(tv)    (tv.tv_sec + (tv.tv_usec / 1.0e6))
  64.  
  65. void
  66. Elapsed(char *msg)
  67. {
  68. #if HAVE_GETTIMEOFDAY
  69.     static    struct    timeval        tv0, tv1;
  70.     static    struct    timezone    tz0, tz1;
  71.     static    int    init;
  72.     if (!init++)
  73.         gettimeofday(&tv0, &tz0);
  74.     gettimeofday(&tv1, &tz1);
  75.     Trace("%10.6f %s\n", SECS(tv1) - SECS(tv0), msg);
  76.     tv0 = tv1;
  77. #endif
  78. }
  79.  
  80. #ifdef    apollo
  81. static
  82. int contains(char *ref, char *tst)
  83. {
  84.     size_t    len    = strlen(ref);
  85.     while (*tst) {
  86.         if (!strncmp(ref,tst++,len))
  87.             return TRUE;
  88.     }
  89.     return FALSE;
  90. }
  91. #endif    /* apollo */
  92.  
  93. void
  94. WalkBack(void)
  95. {
  96. #ifdef    apollo
  97.     static    char    *first    = "\"WalkBack\"",
  98.             *last    = "\"unix_$main\"";
  99.     auto    FILE    *pp;
  100.     auto    char    bfr[BUFSIZ];
  101.     auto    int    ok    = FALSE;
  102.     static    int    count;
  103.  
  104.     Trace("%s %d\n", first, ++count);
  105.     sprintf(bfr, "/com/tb %d", getpid());
  106.     if (!(pp = popen(bfr, "r")))
  107.         perror(bfr);
  108.  
  109.     while (fgets(bfr, sizeof(bfr), pp)) {
  110.         if (ok && contains(last, bfr))
  111.             break;
  112.         else if (contains(first, bfr))
  113.             ok = TRUE;
  114.         else if (ok)
  115.             Trace("%s", bfr);
  116.     }
  117.     (void)fclose(pp);
  118. #endif    /* apollo */
  119. }
  120.  
  121. static    long    count_alloc,
  122.         count_freed;
  123.  
  124. void
  125. fail_alloc(char *msg, char *ptr)
  126. {
  127.     Trace("%s: %p\n", msg, ptr);
  128.     Trace("allocs %ld, frees %ld\n", count_alloc, count_freed);
  129.     WalkBack();
  130. #if NO_LEAKS
  131.     show_alloc();
  132. #endif
  133.     Trace((char *)0);
  134.     abort();
  135. }
  136.  
  137. #if    DOALLOC
  138. #undef    malloc
  139. #undef    realloc
  140. #undef    free
  141.  
  142. typedef    struct    {
  143.     long    size;    /* ...its size */
  144.     char    *text;    /* the actual segment */
  145.     int    note;    /* ...last value of 'count_alloc' */
  146.     } AREA;
  147.  
  148. static    AREA    area[DOALLOC];
  149.  
  150. static    long    maxAllocated,    /* maximum # of bytes allocated */
  151.         nowAllocated,    /* current # of bytes allocated */
  152.         nowPending,    /* current end of 'area[]' table */
  153.         maxPending;    /* maximum # of segments allocated */
  154.  
  155. static
  156. int FindArea(char *ptr)
  157. {
  158.     register int j;
  159.     for (j = 0; j < DOALLOC; j++)
  160.         if (area[j].text == ptr) {
  161.             if (j >= nowPending) {
  162.                 nowPending = j+1;
  163.                 if (nowPending > maxPending)
  164.                     maxPending = nowPending;
  165.             }
  166.             return j;
  167.         }
  168.     return -1;
  169. }
  170.  
  171. static
  172. int record_freed(char *ptr)
  173. {
  174.     register int j;
  175.     if ((j = FindArea(ptr)) >= 0) {
  176.         nowAllocated -= area[j].size;
  177.         /*memset(ptr, 0xdf, area[j].size); -* poison */
  178.         area[j].size = 0;
  179.         area[j].text = 0;
  180.         area[j].note = count_freed;
  181.         if ((j+1) == nowPending) {
  182.             register int    k;
  183.             for (k = j; (k >= 0) && !area[k].size; k--)
  184.                 nowPending = k;
  185.         }
  186.     }
  187.     return j;
  188. }
  189.  
  190. static
  191. int record_alloc(char *newp, char *oldp, unsigned len)
  192. {
  193.     register int    j;
  194.  
  195.     if (newp == oldp) {
  196.         if ((j = FindArea(oldp)) >= 0) {
  197.             nowAllocated -= area[j].size;
  198.             area[j].size = len;
  199.             area[j].note = count_alloc;
  200.         } else
  201.             fail_alloc("could not find", oldp);
  202.     } else {
  203.         if (oldp != 0)
  204.             record_freed(oldp);
  205.         if ((j = FindArea((char *)0)) >= 0) {
  206.             area[j].text = newp;
  207.             area[j].size = len;
  208.             area[j].note = count_alloc;
  209.         } else
  210.             fail_alloc("no room in table", newp);
  211.     }
  212.  
  213.     nowAllocated += len;
  214.     if (nowAllocated > maxAllocated)
  215.         maxAllocated = nowAllocated;
  216.     return len;
  217. }
  218.  
  219. #define    OK_ALLOC(p,q,n)    ((p != 0) && (record_alloc(p,q,n) >= 0))
  220. #define    OK_FREE(p)    ((p != 0) && (record_freed(p) >= 0))
  221. #else
  222. #define    OK_ALLOC(p,q,n)    (p != 0)
  223. #define    OK_FREE(p)    (p != 0)
  224. #endif    /* DOALLOC */
  225.  
  226. #ifdef    DEBUG2
  227. #define    LOG_PTR(msg,num)    Trace("%s %p\n", msg, num);
  228. #define    LOG_LEN(msg,num)    Trace("%s %d\n", msg, num);
  229. #else
  230. #define LOG_PTR(msg,num)
  231. #define    LOG_LEN(msg,num)
  232. #endif
  233.  
  234. /************************************************************************
  235.  *    public entrypoints                        *
  236.  ************************************************************************/
  237. #if DOALLOC
  238. void *
  239. doalloc (void *oldp, unsigned amount)
  240. {
  241.     register void    *newp;
  242.  
  243.     if (oldp != 0)
  244.         oldp -= BEFORE;
  245.     count_alloc += (oldp == 0);
  246. #if 0
  247.     if ((count_alloc > 99914 && count_alloc < 99920)) {
  248.         Trace("doalloc #%d\n", count_alloc);
  249.         WalkBack();
  250.     }
  251. #endif
  252.     LOG_LEN("allocate", amount)
  253.     LOG_PTR("  old = ", oldp)
  254.     amount += (BEFORE+AFTER);    /* patch */
  255.  
  256.     newp = (oldp != 0) ? realloc(oldp, amount) : malloc(amount);
  257.     if (!OK_ALLOC(newp,oldp,amount)) {
  258.         perror("doalloc");
  259.         fail_alloc("doalloc", oldp);
  260.         /*NOT REACHED*/
  261.     }
  262.  
  263.     LOG_PTR("  new = ", newp)
  264.     return (newp+BEFORE);
  265. }
  266.  
  267. /*
  268.  * Entrypoint so we can validate pointers
  269.  */
  270. void
  271. dofree(void *oldp)
  272. {
  273.     oldp -= BEFORE;
  274.     count_freed++;
  275.     LOG_PTR("dealloc ", oldp)
  276.  
  277.     if (OK_FREE(oldp)) {
  278.         free(oldp);
  279.         return;
  280.     }
  281.  
  282.     fail_alloc("free (not found)", oldp);
  283. }
  284. #endif
  285.  
  286. void
  287. show_alloc(void)
  288. {
  289. #if    DOALLOC
  290.     static    char    *format = ".. %-24.24s %10ld\n";
  291.  
  292.     Trace("** allocator metrics:\n");
  293.     Trace(format, "allocs:", count_alloc);
  294.     Trace(format, "frees:",  count_freed);
  295.     {
  296.         register int    j, count = 0;
  297.         register long    total    = 0;
  298.  
  299.         for (j = 0; j < nowPending; j++) {
  300.             if (area[j].text) {
  301.                 if (count++ < 10)
  302.                     Trace("...%d) %ld bytes in alloc #%d:%p\n",
  303.                         j,
  304.                         area[j].size,
  305.                         area[j].note,
  306.                         area[j].text);
  307.                 total += area[j].size;
  308.             }
  309.         }
  310.         Trace(format, "total bytes allocated:",   total);
  311.         Trace(format, "current bytes allocated:", nowAllocated);
  312.         Trace(format, "maximum bytes allocated:", maxAllocated);
  313.         Trace(format, "segment-table length:",    nowPending);
  314.         Trace(format, "current # of segments:",   (long)count);
  315.         Trace(format, "maximum # of segments:",   maxPending);
  316.     }
  317. #endif
  318. }
  319.