From: markh@csd4.csd.uwm.edu (Hunk)
Subject: Re: When should a debugger be used?
Organization: Computing Services Division, University of Wisconsin - Milwaukee
Date: Fri, 14 Aug 1992 17:16:01 GMT

In article <1992Aug12.233904.11067@thinkage.on.ca> atbowler@thinkage.on.ca (Alan Bowler) writes:
>Memory leaks are one of the areas where I have found debuggers to be
>very little use.  I do use it to examine the free memory list, and say
>to myself "this look suspiciously large", but that just tells me there
>MIGHT be a leak.  Finding the actual is has always been more of
>an analysis problem.

Memory leaks (malloc/free faults) are much, much easier to trace without a
debugger, if you're using C.  Substitute your own diagnostic
malloc/realloc/free routines, and do a free-list dump at appropriate times.

These are C diagnostic routines:

Mem.h:
#if DEBUG_MALLOC
#   define TABLE_SIZE 0x1000
   extern void *_Malloc(char Tag, unsigned Size);
   extern void *_Realloc(char Tag, void *X, unsigned Size);
   extern void _Free(void *X);
   extern void ShowAll(void);
#   define Malloc(Tag, Size) _Malloc(Tag, Size)
#   define Relloc(Tag, X, Size) _Realloc(Tag, X, Size)
#   define Free(X) _Free(X)
#else
#   define Malloc(Tag, Size)    malloc(Size)
#   define Relloc(Tag, X, Size) realloc(X, Size)
#   define Free(X)              free(X)
#   define ShowAll()
#endif

Mem.c:
#include <stdio.h>
#include <stdlib.h>
 
typedef void *addr;
struct XX {
   addr X; unsigned Size;
} Tab[TABLE_SIZE], *TP = Tab;
 
struct XX *XP; char Flag;
 
void ShowAll(void) {
   printf("PURGE:\n");
   for (XP = Tab; XP < TP; XP++)
      printf("%8x %4x\n", (int)XP->X, XP->Size);
   if (TP > Tab) exit(0);
}
 
addr _Malloc(char Tag, unsigned Size) {
   addr X = malloc(Size);
   printf("%c (%2d) NEW %d -> %8x\n", Tag, TP - Tab, Size, (int)X);
   if (X == 0) return X;
   for (XP = Tab; XP < TP; XP++) {
      if (X == XP->X) printf("CLASH.\n"), exit(0);
      if (X < XP->X + XP->Size && XP->X < X + Size)
         printf("OVERLAP.\n"), exit(0);
   }
   if (TP - Tab >= TABLE_SIZE)
      fprintf(stderr,"TOO MUCH FOR MEM TO HANDLE.\n"), exit(0);
   TP->X = X, TP->Size = Size, TP++;
   return X;
}
 
addr _Realloc(char Tag, addr X, unsigned Size) {
   struct XX *YP;
   printf("%c (%2d) REA %d %8x -> ", Tag, TP - Tab, Size, (int)X);
   if (X == 0) { XP = TP; goto FOUND; }
   for (XP = Tab; XP < TP; XP++) {
      if (X == XP->X) goto FOUND;
      if (X < XP->X + XP->Size && XP->X < X + Size) printf("OVERLAP.\n"), exit(0);
   }
   printf("\nLOST.\n"), exit(0);
FOUND:
   X = realloc(X, Size);
   printf("%8x\n", (int)X);
   if (X == 0) return X;
   for (YP = Tab; YP < TP; YP++) if (YP != XP) {
      if (X == YP->X) printf("CLASH.\n"), exit(0);
      if (X < YP->X + YP->Size && YP->X < X + Size) printf("OVERLAP.\n"), exit(0);
   }
   if (XP == TP) {
      if (TP - Tab >= TABLE_SIZE) 
         fprintf(stderr,"TOO MUCH FOR MEM.\n"), exit(0);
      TP++;
   }
   XP->X = X, XP->Size = Size;
   return X;
}
 
void _Free(addr X) {
   printf("(%2d) OLD %8x\n", TP - Tab, (int)X);
   if (X == 0) { free(X); return; }
   for (XP = Tab; XP < TP; XP++) {
      if (X == XP->X) goto FOUND;
      if (X < XP->X + XP->Size && XP->X < X) printf("OVERLAP.\n"), exit(0);
   }
   printf("LOST.\n"), exit(0);
FOUND:
   TP--, XP->X = TP->X, XP->Size = TP->Size;
   free(X);
}