Add X{m,c,re}alloc and Xstrdup macros that call an out-of-memory handler on failure.

These wrap the x*alloc or xstrdup functions in compat.c. The handler gets passed
__FILE__, __LINE__ and __func__ (if available) in debugging builds.

Terminating the application process immediately in case of allocation failure
will let us prune many error handling paths and simplify a good portion of code.

git-svn-id: https://svn.eduke32.com/eduke32@4490 1a8010ca-5511-0410-912e-c29ae57300e0
This commit is contained in:
helixhorned 2014-05-30 00:02:16 +00:00
parent 95a6c01045
commit 1d26121514
4 changed files with 128 additions and 0 deletions

View file

@ -775,6 +775,15 @@ static inline void append_ext_UNSAFE(char *outbuf, const char *ext)
Bstrcpy(p, ext); Bstrcpy(p, ext);
} }
#ifdef DEBUGGINGAIDS
extern void xalloc_set_location(int32_t line, const char *file, const char *func);
#endif
void set_memerr_handler(void (*handlerfunc)(int32_t, const char *, const char *));
char *xstrdup(const char *s);
void *xmalloc(bsize_t size);
void *xcalloc(bsize_t nmemb, bsize_t size);
void *xrealloc(void *ptr, bsize_t size);
#ifdef EXTERNC #ifdef EXTERNC
} }
#endif #endif
@ -839,5 +848,29 @@ static inline void append_ext_UNSAFE(char *outbuf, const char *ext)
#define ARRAY_SIZE(Ar) (sizeof(Ar)/sizeof((Ar)[0])) #define ARRAY_SIZE(Ar) (sizeof(Ar)/sizeof((Ar)[0]))
#define ARRAY_SSIZE(Ar) (bssize_t)ARRAY_SIZE(Ar) #define ARRAY_SSIZE(Ar) (bssize_t)ARRAY_SIZE(Ar)
////////// PANICKING ALLOCATION MACROS (wrapping the functions) //////////
#ifdef DEBUGGINGAIDS
// Detection of __func__ or equivalent functionality, found in SDL_assert.h
# if defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) /* C99 supports __func__ as a standard. */
# define EDUKE32_FUNCTION __func__
# elif ((__GNUC__ >= 2) || defined(_MSC_VER))
# define EDUKE32_FUNCTION __FUNCTION__
# else
# define EDUKE32_FUNCTION "???"
# endif
# define EDUKE32_PRE_XALLLOC xalloc_set_location(__LINE__, __FILE__, EDUKE32_FUNCTION)
# define Xstrdup(s) (EDUKE32_PRE_XALLLOC, xstrdup(s))
# define Xmalloc(size) (EDUKE32_PRE_XALLLOC, xmalloc(size))
# define Xcalloc(nmemb, size) (EDUKE32_PRE_XALLLOC, xcalloc(nmemb, size))
# define Xrealloc(ptr, size) (EDUKE32_PRE_XALLLOC, xrealloc(ptr, size))
#else
# define Xstrdup xstrdup
# define Xmalloc xmalloc
# define Xcalloc xcalloc
# define Xrealloc xrealloc
#endif
//////////
#endif // __compat_h__ #endif // __compat_h__

View file

@ -45,6 +45,84 @@
#include "compat.h" #include "compat.h"
#include "baselayer.h" #include "baselayer.h"
////////// PANICKING ALLOCATION FUNCTIONS //////////
static void (*g_MemErrHandler)(int32_t line, const char *file, const char *func);
#ifdef DEBUGGINGAIDS
static const char *g_MemErrFunc = "???";
static const char *g_MemErrFile = "???";
static int32_t g_MemErrLine;
void xalloc_set_location(int32_t line, const char *file, const char *func)
{
g_MemErrLine = line;
g_MemErrFile = file;
if (func)
g_MemErrFunc = func;
}
#endif
static void handle_potential_memerr(void *ptr)
{
if (ptr == NULL)
{
if (g_MemErrHandler)
{
#ifdef DEBUGGINGAIDS
g_MemErrHandler(g_MemErrLine, g_MemErrFile, g_MemErrFunc);
#else
g_MemErrHandler(0, "???", "???");
#endif
}
exit(EXIT_FAILURE);
}
}
void set_memerr_handler(void (*handlerfunc)(int32_t, const char *, const char *))
{
g_MemErrHandler = handlerfunc;
}
char *xstrdup(const char *s)
{
char *ptr = Bstrdup(s);
handle_potential_memerr(ptr);
return ptr;
}
void *xmalloc(bsize_t size)
{
void *ptr = Bmalloc(size);
handle_potential_memerr(ptr);
return ptr;
}
void *xcalloc(bsize_t nmemb, bsize_t size)
{
void *ptr = Bcalloc(nmemb, size);
handle_potential_memerr(ptr);
return ptr;
}
void *xrealloc(void *ptr, bsize_t size)
{
void *newptr = Brealloc(ptr, size);
// According to the C Standard,
// - ptr == NULL makes realloc() behave like malloc()
// - size == 0 make it behave like free() if ptr != NULL
// Since we want to catch an out-of-mem in the first case, this leaves:
if (size != 0)
handle_potential_memerr(newptr);
return newptr;
}
//////////
#ifndef __compat_h_macrodef__ #ifndef __compat_h_macrodef__
void Bassert(int expr) void Bassert(int expr)

View file

@ -10403,12 +10403,20 @@ static void m32script_interrupt_handler(int signo)
} }
} }
static void M32_HandleMemErr(int32_t line, const char *file, const char *func)
{
initprintf("Out of memory in %s:%d (%s)\n", file, line, func);
osdcmd_quit(NULL);
}
int32_t ExtInit(void) int32_t ExtInit(void)
{ {
int32_t rv = 0; int32_t rv = 0;
int32_t i; int32_t i;
char cwd[BMAX_PATH]; char cwd[BMAX_PATH];
set_memerr_handler(&M32_HandleMemErr);
G_AddSearchPaths(); G_AddSearchPaths();
if (getcwd(cwd,BMAX_PATH)) if (getcwd(cwd,BMAX_PATH))

View file

@ -10822,10 +10822,19 @@ void G_PostCreateGameState(void)
A_InitEnemyFlags(); A_InitEnemyFlags();
} }
static void G_HandleMemErr(int32_t line, const char *file, const char *func)
{
static char msg[128];
snprintf(msg, sizeof(msg), "Out of memory in %s:%d (%s)\n", file, line, func);
G_GameExit(msg);
}
static void G_Startup(void) static void G_Startup(void)
{ {
int32_t i; int32_t i;
set_memerr_handler(&G_HandleMemErr);
inittimer(TICRATE); inittimer(TICRATE);
initcrc32table(); initcrc32table();