mirror of
https://github.com/NishiOwO/ircservices5.git
synced 2025-04-21 08:44:38 +00:00
332 lines
8.9 KiB
C
332 lines
8.9 KiB
C
/* Memory management routines.
|
|
* Leak checking based on code by Kelmar (2001/1/13).
|
|
*
|
|
* IRC Services is copyright (c) 1996-2009 Andrew Church.
|
|
* E-mail: <achurch@achurch.org>
|
|
* Parts written by Andrew Kempe and others.
|
|
* This program is free but copyrighted software; see the file GPL.txt 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.)
|
|
*/
|
|
|
|
#if MEMCHECKS
|
|
# define FILELINE , const 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 els, long elsize 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. ************/
|
|
/*************************************************************************/
|
|
|
|
#if MEMCHECKS
|
|
|
|
/*************************************************************************/
|
|
|
|
static long allocated = 0; /* Amount of memory currently allocated */
|
|
static long runtime = 0; /* `allocated' value at init_memory() time */
|
|
|
|
# if SHOWALLOCS
|
|
int showallocs = 1; /* Actually log allocations? */
|
|
# endif
|
|
|
|
typedef struct _smemblock {
|
|
long size; /* Size of this block */
|
|
int32 sig; /* Signature word: 0x5AFEC0DE */
|
|
} MemBlock;
|
|
# define SIGNATURE 0x5AFEC0DE
|
|
# define FREE_SIGNATURE 0xDEADBEEF /* Used for freed memory */
|
|
# define NEW_FILL 0xD017D017 /* New allocs are filled with this */
|
|
# define FREE_FILL 0xBEEF1E57 /* Freed memory is filled with this */
|
|
|
|
# define MEMBLOCK_TO_PTR(mb) ((void *)((char *)(mb) + sizeof(MemBlock)))
|
|
# define PTR_TO_MEMBLOCK(ptr) ((MemBlock *)((char *)(ptr) - sizeof(MemBlock)))
|
|
|
|
|
|
/*************************************************************************/
|
|
/*************************************************************************/
|
|
|
|
/* 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;
|
|
}
|
|
|
|
/*************************************************************************/
|
|
|
|
/* Helper to fill memory with a given 32-bit value. */
|
|
|
|
static inline void fill32(void *ptr, uint32 value, long size)
|
|
{
|
|
register uint32 *ptr32 = ptr;
|
|
register uint32 v = value;
|
|
while (size >= 4) {
|
|
*ptr32++ = v;
|
|
size -= 4;
|
|
}
|
|
if (size > 0)
|
|
memcpy(ptr32, &value, size);
|
|
}
|
|
|
|
/*************************************************************************/
|
|
/*************************************************************************/
|
|
|
|
/* 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;
|
|
void *data;
|
|
|
|
if (size == 0)
|
|
return NULL;
|
|
mb = malloc(size + sizeof(MemBlock));
|
|
if (mb) {
|
|
mb->size = size;
|
|
mb->sig = SIGNATURE;
|
|
data = MEMBLOCK_TO_PTR(mb);
|
|
allocated += size;
|
|
# if SHOWALLOCS
|
|
if (showallocs) {
|
|
log("smalloc(): Allocated %ld bytes at %p (%s:%d)",
|
|
size, data, file, line);
|
|
}
|
|
# endif
|
|
fill32(data, NEW_FILL, size);
|
|
return data;
|
|
} else {
|
|
# if SHOWALLOCS
|
|
if (showallocs) {
|
|
log("mcalloc(): Unable to allocate %ld bytes (%s:%d)",
|
|
size, file, line);
|
|
}
|
|
# endif
|
|
return NULL;
|
|
}
|
|
}
|
|
|
|
/*************************************************************************/
|
|
|
|
void *MCcalloc(long els, long elsize, const char *file, int line)
|
|
{
|
|
MemBlock *mb;
|
|
void *data;
|
|
|
|
if (elsize == 0 || els == 0)
|
|
return NULL;
|
|
mb = malloc(els*elsize + sizeof(MemBlock));
|
|
if (mb) {
|
|
mb->size = elsize * els;
|
|
mb->sig = SIGNATURE;
|
|
data = MEMBLOCK_TO_PTR(mb);
|
|
memset(data, 0, els*elsize);
|
|
allocated += mb->size;
|
|
# if SHOWALLOCS
|
|
if (showallocs) {
|
|
log("scalloc(): Allocated %ld bytes at %p (%s:%d)",
|
|
els*elsize, data, file, line);
|
|
}
|
|
# endif
|
|
return data;
|
|
} else {
|
|
# if 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;
|
|
void *data;
|
|
|
|
if (newsize == 0) {
|
|
MCfree(oldptr, file, line);
|
|
return NULL;
|
|
}
|
|
if (oldptr == NULL)
|
|
return MCmalloc(newsize, file, line);
|
|
oldb = PTR_TO_MEMBLOCK(oldptr);
|
|
if (oldb->sig != SIGNATURE) {
|
|
fatal("Attempt to realloc() an invalid pointer (%p) (%s:%d)",
|
|
oldptr, file, line);
|
|
}
|
|
oldsize = oldb->size;
|
|
newb = realloc(oldb, newsize + sizeof(MemBlock));
|
|
if (newb) {
|
|
newb->size = newsize;
|
|
newb->sig = SIGNATURE; /* should already be set... */
|
|
data = MEMBLOCK_TO_PTR(newb);
|
|
allocated += (newsize - oldsize);
|
|
# if SHOWALLOCS
|
|
if (showallocs) {
|
|
log("srealloc(): Adjusted %ld bytes (%p) to %ld bytes (%p)"
|
|
" (%s:%d)", oldsize, oldptr, newsize, data, file, line);
|
|
}
|
|
# endif
|
|
return data;
|
|
} else {
|
|
# if SHOWALLOCS
|
|
if (showallocs) {
|
|
log("srealloc(): Unable to adjust %ld bytes (%p) to %ld bytes"
|
|
" (%s:%d)", oldsize, oldptr, newsize, file, line);
|
|
}
|
|
# endif
|
|
return NULL;
|
|
}
|
|
}
|
|
|
|
/*************************************************************************/
|
|
|
|
void MCfree(void *ptr, const char *file, int line)
|
|
{
|
|
MemBlock *mb;
|
|
|
|
if (ptr == NULL)
|
|
return;
|
|
mb = PTR_TO_MEMBLOCK(ptr);
|
|
if (mb->sig != SIGNATURE) {
|
|
fatal("Attempt to free() an invalid pointer (%p) (%s:%d)",
|
|
ptr, file, line);
|
|
}
|
|
allocated -= mb->size;
|
|
# if SHOWALLOCS
|
|
if (showallocs) {
|
|
log("sfree(): Released %ld bytes at %p (%s:%d)",
|
|
mb->size, ptr, file, line);
|
|
}
|
|
# endif
|
|
mb->size = FREE_FILL;
|
|
mb->sig = FREE_SIGNATURE;
|
|
fill32(ptr, FREE_FILL, mb->size);
|
|
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 */
|
|
|
|
/*
|
|
* Local variables:
|
|
* c-file-style: "stroustrup"
|
|
* c-file-offsets: ((case-label . *) (statement-case-intro . *))
|
|
* indent-tabs-mode: nil
|
|
* End:
|
|
*
|
|
* vim: expandtab shiftwidth=4:
|
|
*/
|