home *** CD-ROM | disk | FTP | other *** search
/ The C Users' Group Library 1994 August / wc-cdrom-cusersgrouplibrary-1994-08.iso / vol_300 / 322_01 / maltrace.c < prev    next >
C/C++ Source or Header  |  1990-08-06  |  6KB  |  223 lines

  1. /* Code for dynamic memory allocation leak trace tool.  By Mike
  2.    Schwartz, 3-20-87. */
  3.  
  4. #include "btree.h"
  5.  
  6. BTREE MalBtree = NULL;
  7. int MalTraceEnbld = 0; /* Flag to enable/disable tracing of malloc/free
  8.                            calls.  Need to turn it off sometime (e.g.,
  9.                            during printf calls, since printf (indirectly)
  10.                            calls malloc/free, and during
  11.                            uninteresting/debugged initialization code) */
  12.  
  13. int MallocCallCounter = 0;
  14. int NumPendingMallocs = 0;
  15. int MalBrkNum = -1; /* Malloc call number at which to call MalBreak routine */
  16. int MalBrkSize = -1; /* Malloc size at which to call MalBreak routine */
  17. struct list {
  18.     KEY MalAddr;
  19.     struct list *prev;
  20.     struct list *next;
  21. };
  22. struct list *ListHead = NULL, *ListTail = NULL;
  23.  
  24. char *
  25. malloc(nbytes)
  26.     unsigned nbytes;
  27. {
  28.     char *mmalloc(), *MalAddr;
  29.     struct list *lp;
  30.     DATUM datum, *dp;
  31.  
  32.     MalAddr = mmalloc(nbytes);
  33.     if (MalTraceEnbld == 1) {    /* printf calls malloc/free */
  34.         datum.key = MalAddr;
  35.         datum.inf.MalCallNum = ++MallocCallCounter;
  36.         datum.inf.MalSize = nbytes;
  37.         datum.inf.MalAddr = MalAddr;
  38.         MalBtree = Insert(datum, MalBtree);
  39.         NumPendingMallocs++;
  40.         dp = Search(MalAddr, MalBtree);
  41.         /* Insert in ordered doubly linked list of mallocs */
  42.         lp = (struct list *) mmalloc(sizeof(struct list));
  43.         lp->MalAddr = MalAddr;
  44.         (dp->inf).lp = lp;
  45.         if (ListHead == NULL) {
  46.             ListHead = lp;
  47.             lp->prev = NULL;
  48.         } else {
  49.             ListTail->next = lp;
  50.             lp->prev = ListTail;
  51.         }
  52.         lp->next = NULL;
  53.         ListTail = lp;
  54. #ifdef DEBUG_MAL_TRACE
  55.         MalTraceEnbld = 0;    /* printf calls malloc/free */
  56.         printf("\tmalloc(%d)=x%x\n", nbytes, MalAddr);
  57.         fflush(stdout);
  58.         MalTraceEnbld = 1;
  59. #endif DEBUG_MAL_TRACE
  60.         if (MallocCallCounter == MalBrkNum || MalBrkSize == nbytes)
  61.             MalBreak();    /* So we can hit dbx(1) breakpoint */
  62.     }
  63.     return(MalAddr);
  64. }
  65.  
  66. free(cp)
  67.     char *cp;
  68. {   
  69.     struct list *lp;
  70.     DATUM datum, *dp;
  71.  
  72.     if (MalTraceEnbld == 1) {
  73.         dp = Search(cp, MalBtree);
  74.         if (dp == NULL) {
  75.             MalTraceEnbld = 0;    /* printf calls malloc/free */
  76.             printf("\tfree(x%x): not malloc'd with MalTraceEnbld\n", cp);
  77.             MalTraceEnbld = 1;
  78.             UntracedFree();
  79.             ffree(lp);
  80.             return;
  81.         }
  82.         NumPendingMallocs--;
  83.  
  84.         lp = (dp->inf).lp;
  85.  
  86.         /* Delete from ordered doubly linked list of mallocs */
  87.         if (ListHead == lp) {
  88.             ListHead = ListHead->next;
  89.         } else {
  90.             (lp->prev)->next = lp->next;
  91.         }
  92.         if (ListTail == lp) {
  93.             ListTail = lp->prev;
  94.         } else {
  95.             (lp->next)->prev = lp->prev;
  96.         }
  97.         ffree(lp);
  98.         MalBtree = Delete(cp, MalBtree);
  99.  
  100. #ifdef DEBUG_MAL_TRACE
  101.         MalTraceEnbld = 0;    /* printf calls malloc/free */
  102.         printf("\tfree(x%x)\n", cp);
  103.         fflush(stdout);
  104.         MalTraceEnbld = 1;
  105. #endif DEBUG_MAL_TRACE
  106.     }
  107.     ffree(cp);
  108. }
  109.  
  110. /* Don't need to modify btree/linked list structures here, since realloc
  111.    will call malloc/free if it needs to, which will do the right thing. */
  112. char *
  113. realloc(cp, nbytes)
  114.     char *cp; 
  115.     unsigned nbytes;
  116. {   
  117.     char *rrealloc(), *tmp;
  118.  
  119.     tmp=rrealloc(cp, nbytes);
  120. #ifdef DEBUG_MAL_TRACE
  121.     if (MalTraceEnbld) {
  122.         MalTraceEnbld = 0;    /* printf calls malloc/free */
  123.         printf("\trealloc(x%x, %d)=x%x\n", cp, nbytes, tmp);
  124.         MalTraceEnbld = 1;
  125.     }
  126. #endif DEBUG_MAL_TRACE
  127.     return(tmp);
  128. }
  129.  
  130. /* If n > 0, print (at most) the first n entries of list of pending info
  131.    (i.e., mallocs which haven't yet been free'd).  If n == 0, print all
  132.    pending entries.  If n < 0, print (at most) the last -n pending entries */
  133. PMal(n)
  134. int n;
  135. {
  136.     struct list *lp, *Start;
  137.     DATUM datum, *dp;
  138.     int i;
  139.     int MalTraceInitialVal = MalTraceEnbld;
  140.     char *OrdSuffix();
  141.  
  142.     MalTraceEnbld = 0;    /* puts and printf call malloc/free */
  143.     if (ListHead == NULL)
  144.         puts("\tNo pending mallocs");
  145.     else {
  146.         Start = ListHead;
  147.         if (n == 0)
  148.             printf("\tPending mallocs (%d total):\n",
  149.                 NumPendingMallocs);
  150.         else if (n == 1)
  151.             printf("\tFirst pending malloc (of %d):\n",
  152.                 NumPendingMallocs);
  153.         else if (n > 1)
  154.             printf("\tFirst %d pending mallocs (of %d):\n",
  155.                 n, NumPendingMallocs);
  156.         else {
  157.             if (n == -1)
  158.                 printf("\tLast pending malloc (of %d):\n",
  159.                     NumPendingMallocs);
  160.             else
  161.                 printf("\tLast %d pending mallocs (of %d):\n",
  162.                     -n, NumPendingMallocs);
  163.             for (Start = ListTail, i = n + 1;
  164.                  Start != NULL && i < 0; Start = Start->prev, i++) {
  165.             }
  166.             if (Start == NULL)
  167.                 Start = ListHead;
  168.             n = -n;
  169.         }
  170.         for (lp = Start, i = 0; lp != NULL; lp = lp->next, i++) {
  171.             if (n != 0 && i >= n)
  172.                 break;
  173.             dp = Search(lp->MalAddr, MalBtree);
  174.             printf("\t%d%s malloc(%d): x%x\n",
  175.                 (dp->inf).MalCallNum,
  176.                 OrdSuffix((dp->inf).MalCallNum),
  177.                 (dp->inf).MalSize,
  178.                 (dp->inf).MalAddr);
  179.         }
  180.     }
  181.     MalTraceEnbld = MalTraceInitialVal;
  182.     return;
  183. }
  184.  
  185. /* Return a character string suffix for the ordinal number n */
  186. char *
  187. OrdSuffix(n)
  188. int n;
  189. {
  190.     if ( (n % 100) > 10 && (n % 100) < 20)
  191.         return("th");
  192.     switch (n % 10) {
  193.         case 0: case 4: case 5: case 6: case 7: case 8: case 9:
  194.             return("th");
  195.         case 1:
  196.             return("st");
  197.         case 2:
  198.             return("nd");
  199.         case 3:
  200.             return("rd");
  201.     }
  202. }
  203.  
  204.  
  205.  
  206. /* Routines called to allow user to set dbx(1) breakpoints */
  207.  
  208. /* Breakpoint in suspected leaking malloc call */
  209. MalBreak()
  210. {
  211. }
  212.  
  213. /* Breakpoint in free call made on data not malloc'd with tracing enabled */
  214. UntracedFree()
  215. {
  216. }
  217.  
  218. /* Set MalBrkNum to the next malloc call, for the next iteration of tracing */
  219. NextMal()
  220. {
  221.     MalBrkNum = MallocCallCounter + 1;
  222. }
  223.