/* Memory management routines.
* Leak checking based on code by Kelmar (2001/1/13)
*
* IRC Services is copyright (c) 1996-2007 Andrew Church.
* E-mail: <achurch@achurch.org>
* 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 */
syntax highlighted by Code2HTML, v. 0.9.1