/* Memory management routines. * Leak checking based on code by Kelmar (2001/1/13) * * IRC Services is copyright (c) 1996-2007 Andrew Church. * E-mail: * Parts written by Andrew Kempe and others. * This program is free but copyrighted software; see the file COPYING for * details. */ #define NO_MEMREDEF #include "services.h" /*************************************************************************/ /*************************************************************************/ /* smalloc, scalloc, srealloc, sstrdup: * Versions of the memory allocation functions which will cause the * program to terminate with an "Out of memory" error if the memory * cannot be allocated. (Hence, the return value from these functions * is never NULL, except for smalloc()/scalloc() called with a size of * zero.) */ #ifdef MEMCHECKS # define FILELINE , char *file, int line # define xmalloc(a) MCmalloc(a,file,line) # define xsmalloc(a) smalloc(a,file,line) # define xcalloc(a,b) MCcalloc(a,b,file,line) # define xrealloc(a,b) MCrealloc(a,b,file,line) # define xfree(a) MCfree(a,file,line) #else # define FILELINE /*nothing*/ # define xmalloc(a) malloc(a) # define xsmalloc(a) smalloc(a) # define xcalloc(a,b) calloc(a,b) # define xrealloc(a,b) realloc(a,b) # define xfree(a) free(a) #endif /*************************************************************************/ void *smalloc(long size FILELINE) { void *buf; if (size == 0) return NULL; buf = xmalloc(size); if (buf == NULL) raise(SIGUSR1); return buf; } /*************************************************************************/ void *scalloc(long elsize, long els FILELINE) { void *buf; if (elsize == 0 || els == 0) return NULL; buf = xcalloc(elsize, els); if (buf == NULL) raise(SIGUSR1); return buf; } /*************************************************************************/ void *srealloc(void *oldptr, long newsize FILELINE) { void *buf; if (newsize == 0) { xfree(oldptr); return NULL; } buf = xrealloc(oldptr, newsize); if (buf == NULL) raise(SIGUSR1); return buf; } /*************************************************************************/ char *sstrdup(const char *s FILELINE) { char *t = xsmalloc(strlen(s) + 1); strcpy(t, s); /* safe, obviously */ return t; } /*************************************************************************/ /************ Everything from here down is MEMCHECKS-related. ************/ /*************************************************************************/ #ifdef MEMCHECKS /*************************************************************************/ static long allocated = 0; /* Amount of memory currently allocated */ static long runtime = 0; /* `allocated' value at init_memory() time */ #ifdef SHOWALLOCS int showallocs = 1; /* Actually log allocations? */ #endif typedef struct _smemblock { long size; /* Size of this block */ int32 sig; /* Signature word: 0x5AFEC0DE */ void *data; /* Start of the user's data */ } MemBlock; # define SIGNATURE 0x5AFEC0DE # define FREE_SIGNATURE 0xDEADBEEF /* Used for freed memory */ /*************************************************************************/ /*************************************************************************/ /* Leak-checking initialization and exit code. */ static void show_leaks(void) { if (runtime >= 0 && (allocated - runtime) > 0) { log("SAFEMEM: There were %ld bytes leaked on exit!", (allocated - runtime)); } else { log("SAFEMEM: No memory leaks detected."); } } void init_memory(void) { runtime = allocated; log("init_memory(): runtime = %ld", runtime); atexit(show_leaks); } /* Used to avoid memory-leak message from the parent process */ void uninit_memory(void) { runtime = -1; } /*************************************************************************/ /* Substitutes for malloc() and friends. memory.h redefines malloc(), etc. * to these functions if MEMCHECKS is defined. */ /*************************************************************************/ void *MCmalloc(long size, const char *file, int line) { MemBlock *mb; if (size == 0) return NULL; mb = malloc(size + sizeof(MemBlock)); if (mb) { mb->size = size; mb->sig = SIGNATURE; mb->data = (void *)((char *)(mb) + sizeof(MemBlock)); allocated += size; # ifdef SHOWALLOCS if (showallocs) { log("smalloc(): Allocated %ld bytes at %p (%s:%d)", size, mb->data, file, line); } # endif return mb->data; } else { # ifdef SHOWALLOCS if (showallocs) { log("mcalloc(): Unable to allocate %ld bytes (%s:%d)", size, file, line); } # endif return NULL; } } /*************************************************************************/ void *MCcalloc(long elsize, long els, const char *file, int line) { MemBlock *mb; if (elsize == 0 || els == 0) return NULL; mb = malloc(elsize * els + sizeof(MemBlock)); if (mb) { mb->size = elsize * els; mb->sig = SIGNATURE; mb->data = (void *)((char *)(mb) + sizeof(MemBlock)); memset(mb->data, 0, elsize * els); allocated += mb->size; # ifdef SHOWALLOCS if (showallocs) { log("scalloc(): Allocated %ld bytes at %p (%s:%d)", els*elsize, mb->data, file, line); } # endif return mb->data; } else { # ifdef SHOWALLOCS if (showallocs) { log("scalloc(): Unable to allocate %ld bytes (%s:%d)", els*elsize, file, line); } # endif return NULL; } } /*************************************************************************/ void *MCrealloc(void *oldptr, long newsize, const char *file, int line) { MemBlock *newb, *oldb; long oldsize; # ifdef SHOWALLOCS void *olddata; # endif if (newsize == 0) { MCfree(oldptr, file, line); return NULL; } if (oldptr == NULL) return MCmalloc(newsize, file, line); oldb = (MemBlock *)((char *)(oldptr) - sizeof(MemBlock)); if (oldb->sig != SIGNATURE) { fatal("Attempt to realloc() an invalid pointer (%p) (%s:%d)", oldptr, file, line); } # ifdef SHOWALLOCS olddata = oldb->data; # endif oldsize = oldb->size; newb = realloc(oldb, newsize + sizeof(MemBlock)); if (newb) { newb->size = newsize; newb->sig = SIGNATURE; newb->data = (void *)((char *)(newb) + sizeof(MemBlock)); /* Adjust our tracker acordingly */ allocated += (newsize - oldsize); # ifdef SHOWALLOCS if (showallocs) { log("srealloc(): Adjusted %ld bytes (%p) to %ld bytes (%p)" " (%s:%d)", oldsize, olddata, newsize, newb->data, file, line); } # endif return newb->data; } else { # ifdef SHOWALLOCS if (showallocs) { log("srealloc(): Unable to adjust %ld bytes (%p) to %ld bytes" " (%s:%d)", oldsize, olddata, newsize, file, line); } # endif return NULL; } } /*************************************************************************/ void MCfree(void *ptr, const char *file, int line) { MemBlock *mb; if (ptr == NULL) return; mb = (MemBlock *)((char *)(ptr) - sizeof(MemBlock)); if (mb->sig != SIGNATURE) { fatal("Attempt to free() an invalid pointer (%p) (%s:%d)", ptr, file, line); } allocated -= mb->size; # ifdef SHOWALLOCS if (showallocs) { log("sfree(): Released %ld bytes at %p (%s:%d)", mb->size, mb->data, file, line); } # endif mb->sig = FREE_SIGNATURE; free(mb); } /*************************************************************************/ char *MCstrdup(const char *s, const char *file, int line) { char *t = MCmalloc(strlen(s) + 1, file, line); strcpy(t, s); /* safe, obviously */ return t; } /*************************************************************************/ #endif /* MEMCHECKS */