如何让OS X malloc在失败时自动中止?

and*_*otn 6 c malloc macos

Matasano博客呼吁"检查的返回值malloc()"一"C程序反成语."相反malloc()应该自动调用abort()如果失败了你.这个论点是,因为如果malloc()失败,你通常会想要中止程序,这应该是默认行为,而不是你必须费力地键入的东西 - 或者可能忘记输入!-every time.

没有深入了解这个想法的优点,最简单的方法是什么?我正在寻找能够自动检测其他库函数的内存分配失败的东西asprintf().便携式解决方案会很精彩,但我也会对特定于mac的东西感到满意.


总结下面的最佳答案:

Mac运行时解决方案

MallocErrorAbort=1在运行程序之前设置环境变量.自动适用于所有内存分配功能.

Mac/linux运行时解决方案

使用动态库填充malloc()程序在运行时使用LD_PRELOAD或加载自定义包装器DYLD_INSERT_LIBRARIES.你可能会想包装calloc(),realloc(),温度.同样.

Mac/linux编译解决方案

定义您自己的malloc()free()功能,并使用dyld(RTLD_NEXT, "malloc") 此处所示访问系统版本.同样,你可能会想包装calloc(),realloc(),温度.同样.

#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;
}
Run Code Online (Sandbox Code Playgroud)

Linux编译解决方案

使用__malloc_hook__realloc_hookglibc手册中所述.

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;
}
Run Code Online (Sandbox Code Playgroud)

为了完整起见,你可能会想包装calloc(),realloc()以及在规定的其它功能malloc_zone_t/usr/include/malloc/malloc.h也是如此.

Jes*_*mos 5

只需包含malloc()一些my_malloc()执行此操作的函数.在很多情况下,它实际上可能处理不能分配内存,因此这种行为是不可取的.添加功能很容易,malloc()但不能删除它,这可能就是它以这种方式运行的原因.

另外要记住的是,这是一个你正在调用的库.你想要一个图书馆电话,并让图书馆杀死你的应用程序,而你却无法发表意见吗?

我想我错过了关于asprintf但是libc导出了一些你可以使用的钩子(valgrind本质上是什么)让你覆盖malloc行为.这里是钩子本身的参考,如果你足够了解C,那就不难了.

http://www.gnu.org/savannah-checkouts/gnu/libc/manual/html_node/Hooks-for-Malloc.html