/* $Id: xmalloc.c 5381 2002-03-31 22:35:47Z rra $ ** ** malloc routines with failure handling. ** ** Usage: ** ** extern xmalloc_handler_t memory_error; ** extern const char *string; ** char *buffer; ** ** xmalloc_error_handler = memory_error; ** buffer = xmalloc(1024); ** xrealloc(buffer, 2048); ** free(buffer); ** buffer = xcalloc(1024); ** free(buffer); ** buffer = xstrdup(string); ** free(buffer); ** buffer = xstrndup(string, 25); ** ** xmalloc, xcalloc, xrealloc, and xstrdup behave exactly like their C ** library counterparts without the leading x except that they will never ** return NULL. Instead, on error, they call xmalloc_error_handler, ** passing it the name of the function whose memory allocation failed, the ** amount of the allocation, and the file and line number where the ** allocation function was invoked (from __FILE__ and __LINE__). This ** function may do whatever it wishes, such as some action to free up ** memory or a call to sleep to hope that system resources return. If the ** handler returns, the interrupted memory allocation function will try its ** allocation again (calling the handler again if it still fails). ** ** xstrndup behaves like xstrdup but only copies the given number of ** characters. It allocates an additional byte over its second argument and ** always nul-terminates the string. ** ** The default error handler, if none is set by the caller, prints an error ** message to stderr and exits with exit status 1. An error handler must ** take a const char * (function name), size_t (bytes allocated), const ** char * (file), and int (line). ** ** xmalloc will return a pointer to a valid memory region on an xmalloc of 0 ** bytes, ensuring this by allocating space for one character instead of 0 ** bytes. ** ** The functions defined here are actually x_malloc, x_realloc, etc. The ** header file defines macros named xmalloc, etc. that pass the file name ** and line number to these functions. */ /* Used for unused parameters to silence gcc warnings. */ #define UNUSED __attribute__((__unused__)) /* Make available the bool type. */ #if INN_HAVE_STDBOOL_H # include #else # undef true # undef false # define true (1) # define false (0) # ifndef __cplusplus # define bool int # endif #endif /* INN_HAVE_STDBOOL_H */ #include #include #include #include #include #include /* Failure handler takes the function, the size, the file, and the line. */ typedef void (*xmalloc_handler_t)(const char *, size_t, const char *, int); /* Assign to this variable to choose a handler other than the default, which just calls sysdie. */ extern xmalloc_handler_t xmalloc_error_handler; /* The default error handler. */ void xmalloc_fail(const char *function, size_t size, const char *file, int line) { sysdie("failed to %s %lu bytes at %s line %d", function, (unsigned long) size, file, line); } /* Assign to this variable to choose a handler other than the default. */ xmalloc_handler_t xmalloc_error_handler = xmalloc_fail; void * x_malloc(size_t size, const char *file, int line) { void *p; size_t real_size; real_size = (size > 0) ? size : 1; p = malloc(real_size); while (p == NULL) { (*xmalloc_error_handler)("malloc", size, file, line); p = malloc(real_size); } return p; } void * x_calloc(size_t n, size_t size, const char *file, int line) { void *p; n = (n > 0) ? n : 1; size = (size > 0) ? size : 1; p = calloc(n, size); while (p == NULL) { (*xmalloc_error_handler)("calloc", n * size, file, line); p = calloc(n, size); } return p; } void * x_realloc(void *p, size_t size, const char *file, int line) { void *newp; newp = realloc(p, size); while (newp == NULL && size > 0) { (*xmalloc_error_handler)("realloc", size, file, line); newp = realloc(p, size); } return newp; } char * x_strdup(const char *s, const char *file, int line) { char *p; size_t len; len = strlen(s) + 1; p = malloc(len); while (p == NULL) { (*xmalloc_error_handler)("strdup", len, file, line); p = malloc(len); } memcpy(p, s, len); return p; } char * x_strndup(const char *s, size_t size, const char *file, int line) { char *p; p = malloc(size + 1); while (p == NULL) { (*xmalloc_error_handler)("strndup", size + 1, file, line); p = malloc(size + 1); } memcpy(p, s, size); p[size] = '\0'; return p; }