#include "jcabc2ps.h" #include "misc.h" #define Chunk struct _chunk_ Chunk { void *p; // Pointer int s; // Size int u; // Usage char d[16]; // Description } *chunk = 0; int chunks = 0; // Chunk count int chunkm = 0; // Chunk count max long chunktotal = 0; // Chunk size total #define EXTRA 64 // Extra bytes on each chunk #define MEM_FREE 1 // Freed chunk of memory #define MEM_INUSE 2 // Alloc'd chunk of memory imin(int i, int j) {if (i <= j) return i; return j;} imax(int i, int j) {if (i >= j) return i; return j;} int FindChunk( void *p, // Pointer to chunk char *d) // Description { int i; for (i = 0; i < chunkm; i++) { if (chunk[i].p == p) { return i; } } return -1; } /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Register a new chunk of memory. The chunk[] list is our list of known * chunks. It's valid for a chunk to be added twice, since a freed chunk may * be malloc'd again later. So we look through the list for the chunk, and if * we find it, we use its old entry. We also complain if we are asked to make * a dubious change of usage. */ NewChunk( void *p, // Pointer to chunk int s, // Size of chunk (bytes) char *d, // Description int u) // Usage code { char *F = "NewChunk"; int i, n; V3 "%s: %08X s=%d u=%d=%s d=\"%s\" ...\n",F,p,s,u,(u==1?"FREE":u==2?"INUSE":"???"),d V; if (chunks >= chunkm) { V3 "%s: Increase chunk table size from %d to %d.\n",F,chunkm,chunkm+100 V; chunk = (Chunk*)realloc(chunk,(chunkm+100)*sizeof(Chunk)); if (!chunk) { V1 "%s: ### OUT OF SPACE (can't get %d bytes for chunk list) ###\n",F,(chunkm+100)*sizeof(Chunk) V; chunkm = 0; return; } bzero(chunk+chunkm,100*sizeof(Chunk)); // Make sure the new entries are zeroed out. chunkm += 100; // Up the chunk count. } for (i = 0; i < chunkm; i++) { V3 "%s: i=%d u=%d\n",F,i,u V; switch (chunk[i].u) { default: V1 "%s: ### MEM_type %d unknown, treated as MEM_INUSE ###\n",F,chunk[i].u V; case MEM_INUSE: if ((chunk[i].p != 0) && (chunk[i].p != p)) { continue; /* It's another block */ } if (chunk[i].p == p) { V1 "%s: ### chunk %08X already marked INUSE ###\n",F,p V; return; } if (chunk[i].p == p) { if (u == MEM_INUSE) { V1 "%s: ### chunk %08X already marked INUSE ###\n",F,p V; return; } } /* chunk[i].p == 0 but marked INUSE */ case 0: // Empty chunk struct chunktotal += (2 * s); case MEM_FREE: // Chunk struct is free; use it if (u == MEM_FREE) { V1 "%s: ### chunk %08X already marked FREE ###\n",F,p V; return; } n = imin(15,strlen(d)); // Use up to 15 bytes of description chunk[i].u = u; chunk[i].s = s; chunktotal += s; chunk[i].p = p; strncpy(chunk[i].d,d,n); chunk[i].d[n] = 0; V3 "%s: %08X s=%d u=%d d=\"%s\" free chunk %d (total size = %d).\n",F,p,chunk[i].s,chunk[i].u,chunk[i].d,i,chunktotal V; if (i >= chunks) chunks = i + 1; return; } } V1 "%s: ### AWK!! Ran off end of chunk list ###\n",F V; } /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Debug wrapper around malloc(). We also call NewChunk() to register the chunk * with our mem-debug gimmick. */ void *Malloc( int n, /* Number of bytes */ char* d) /* Description, for messages */ { char* F = "Malloc"; void* p = 0; n += (2 * EXTRA); // For debugging memory problems. V3 "%s: Get %d bytes for \"%s\"\n",F,n,d V; if (p = (void*)malloc(n)) { p += EXTRA; V3 "%s: %08X %d bytes \"%s\"\n",F,p,n,d V; NewChunk(p,n,d,MEM_INUSE); return p; } V3 "%s: ### Can't get %d bytes for %s ###\n",F,n,d V; return 0; } /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Debug wrapper around free(). This uses our mem-debug stuff to spot attempts * to free stuff that wasn't malloc'd or to free a chunk twice. */ void Free( void *p, char *d) { char *F = "Free"; int i, j; if (!p) { V1 "%s: ### Attempt to free block %08X ###\n",F,p V; return; } if ((i = j = FindChunk(p,d)) < 0) { V1 "%s: ### Attempt to free unallocated block %08X ###\n",F,p V; i = i / (i - j); // BOMB HERE! return; } if (chunk[i].u != MEM_INUSE) { V1 "%s: ### Attempt to free block %08X that is not INUSE ###\n",F,p V; return; } chunktotal -= chunk[i].s; V3 "%s: %08X \"%s\" is %d-byte chunk %d, total=%d.\n",F,p,d,chunk[i].s,i,chunktotal V; chunk[i].u = MEM_FREE; p -= EXTRA; free(p); }