如何实现calloc

时间:2017-10-20 16:58:22

标签: c malloc standards calloc copy-on-write

我正在尝试重写malloc和calloc,我的问题是关于calloc的实现,而不是如何使用它。

应始终使用calloc()代替malloc()+memset(),因为它可以利用copy-on-write(COW)。

有些calloc的实现如下:

void * calloc(size_t nelem, size_t elsize)
{
    void *p;

    p = malloc (nelem * elsize);
    if (p == 0)
        return (p);

    bzero (p, nelem * elsize);
    return (p);
}

但他们根本不使用COW(他们不检查溢出)。

如果这些实现没有调用bzero(),则必须假设他们收到的mmap个ed页面为零填充。它们可能是出于安全原因,我们不希望其他进程的数据泄露,但我找不到任何关于此的标准参考。

我们可以MAP_ANON mmap来代替/dev/zero使用fd = open("/dev/zero", O_RDWR); a = mmap (0, 4096e4, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_FILE, fd, 0);

/dev/zero

但POSIX没有规定sudo mv /dev/zero /dev/foo,而且可以轻松执行calloc(),从而破坏我的实施。

有效重写# ignore all files except for template config files !/ /* !exception_dir/ !.gitignore !init.sh !blah.template.json 的正确方法是什么,尊重写时复制?

1 个答案:

答案 0 :(得分:2)

Pure POSIX不支持匿名内存映射,并且没有比calloc更低级别的接口来分配零内存。

现有的POSIX实现通过MAP_ANONMAP_ANONYMOUS标志(或历史上,通过/dev/zero的映射)支持匿名私有内存映射作为扩展。内核确保应用程序只看到归零内存。 (也有较旧的接口,例如brksbrk,但它们很难使用非线程安全的。)

malloc函数族的实现通常使用mmap分配更大的块,并为每个块保留一个水印指针,指示哪个部分已经分配给应用程序至少一次(通过{ {1}} / malloc / realloc,无关紧要)。 calloc在返回分配之前检查水印指针,如果之前应用程序使用了内存,则会清除它。否则,它会被直接返回,因为已知它是新鲜的,因此已被内核清除。

也可以使用calloc直接分配大块。但是内核最终也必须清除内存(在使用它来支持触发写时复制错误的映射之前),所以如果分配比实际需要大得多,那么这只是一个明显的胜利,并且大多数部分都是从未写过。