Matasano's blog calls "Checking the return value malloc()" a "Anti-Idiom Programming". Instead, it malloc()should automatically call abort()for you if it fails. The argument is that since you usually want to interrupt the program if it malloc()doesn’t work, this should be the default behavior instead of what you need to type with difficulty - or maybe forget to enter! - Every time.
Without delving into the merits of an idea, what is the easiest way to customize this? I was looking for something that would automatically detect failures in memory allocation by other library functions such as asprintf(). A portable solution would be great, but Id would also be pleased with something Mac specific.
To summarize the best answers below:
Mac OS Solution
Set the environment variable MallocErrorAbort=1before running your program. Automatically works for all memory allocation functions.
Mac / linux runtime solution
Use the shim dynamic library to load a custom shell malloc()at run time with LD_PRELOADor DYLD_INSERT_LIBRARIES. Most likely, you'll want to wrap calloc(), realloc(), & c. also.
Mac / linux compiled solution
malloc() free() dyld(RTLD_NEXT, "malloc") . , , , calloc(), realloc(), & c. .
#include <dlfcn.h>
#include <stdio.h>
#include <stdlib.h>
void *(*system_malloc)(size_t) = NULL;
void* malloc(size_t bytes) {
if (system_malloc == NULL) {
system_malloc = dlsym(RTLD_NEXT, "malloc");
}
void* ret = system_malloc(bytes);
if (ret == NULL) {
perror("malloc failed, aborting");
abort();
}
return ret;
}
int main() {
void* m = malloc(10000000000000000l);
if (m == NULL) {
perror("malloc failed, program still running");
}
return 0;
}
Linux
__malloc_hook __realloc_hook, glibc manual.
Mac
malloc_default_zone() , , zone->malloc:
#include <malloc/malloc.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/mman.h>
#include <unistd.h>
static void* (*system_malloc)(struct _malloc_zone_t *zone, size_t size);
static void* my_malloc(struct _malloc_zone_t *zone, size_t size) {
void* ret = system_malloc(zone, size);
if (ret == NULL) {
perror("malloc failed, aborting");
abort();
}
return ret;
}
int main() {
malloc_zone_t *zone = malloc_default_zone();
if (zone->version != 8) {
fprintf(stderr, "Unknown malloc zone version %d\n", zone->version);
abort();
}
system_malloc = zone->malloc;
if (mprotect(zone, getpagesize(), PROT_READ | PROT_WRITE) != 0) {
perror("munprotect failed");
abort();
}
zone->malloc = my_malloc;
if (mprotect(zone, getpagesize(), PROT_READ) != 0) {
perror("mprotect failed");
abort();
}
void* m = malloc(10000000000000000l);
if (m == NULL) {
perror("malloc failed, program still running");
}
return 0;
}
, , calloc(), realloc() , malloc_zone_t /usr/include/malloc/malloc.h.