/* * malloc routines with failure handling. * * Usage: * * extern xmalloc_handler_t memory_error; * extern const char *string; * char *buffer; * va_list args; * * 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); * free(buffer); * xasprintf(&buffer, "%s", "some string"); * free(buffer); * xvasprintf(&buffer, "%s", args); * * 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. * * xasprintf and xvasprintf behave just like their GNU glibc library * implementations except that they do the same checking as described above. * xasprintf will only be able to provide accurate file and line information * on systems that support variadic macros. * * 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. * * Copyright (c) 2004, 2005, 2006 * by Internet Systems Consortium, Inc. ("ISC") * Copyright (c) 1991, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, * 2002, 2003 by The Internet Software Consortium and Rich Salz * * See LICENSE for licensing terms. */ #include #include #include #include #include /* * 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_type 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; } int x_vasprintf(char **strp, const char *fmt, va_list args, const char *file, int line) { va_list args_copy; int status; va_copy(args_copy, args); status = vasprintf(strp, fmt, args_copy); va_end(args_copy); while (status < 0 && errno == ENOMEM) { va_copy(args_copy, args); status = vsnprintf(NULL, 0, fmt, args_copy); va_end(args_copy); (*xmalloc_error_handler)("vasprintf", status + 1, file, line); va_copy(args_copy, args); status = vasprintf(strp, fmt, args_copy); va_end(args_copy); } return status; } #if HAVE_C99_VAMACROS || HAVE_GNU_VAMACROS int x_asprintf(char **strp, const char *file, int line, const char *fmt, ...) { va_list args, args_copy; int status; va_start(args, fmt); va_copy(args_copy, args); status = vasprintf(strp, fmt, args_copy); va_end(args_copy); while (status < 0 && errno == ENOMEM) { va_copy(args_copy, args); status = vsnprintf(NULL, 0, fmt, args_copy); va_end(args_copy); (*xmalloc_error_handler)("asprintf", status + 1, file, line); va_copy(args_copy, args); status = vasprintf(strp, fmt, args_copy); va_end(args_copy); } return status; } #else /* !(HAVE_C99_VAMACROS || HAVE_GNU_VAMACROS) */ int x_asprintf(char **strp, const char *fmt, ...) { va_list args, args_copy; int status; va_start(args, fmt); va_copy(args_copy, args); status = vasprintf(strp, fmt, args_copy); va_end(args_copy); while (status < 0 && errno == ENOMEM) { va_copy(args_copy, args); status = vsnprintf(NULL, 0, fmt, args_copy); va_end(args_copy); (*xmalloc_error_handler)("asprintf", status + 1, __FILE__, __LINE__); va_copy(args_copy, args); status = vasprintf(strp, fmt, args_copy); va_end(args_copy); } return status; } #endif /* !(HAVE_C99_VAMACROS || HAVE_GNU_VAMACROS) */