malloc 像 calloc 一样工作

malloc works like calloc

当malloc 运行时,它产生内存块,它没有设置任何值,它包含垃圾值。当 calloc 运行 时,一些事件像 malloc 函数一样发生,但有一个区别。当 calloc 生成新块时,它在块中设置 0(零)。

#include <stdio.h>
#include <stdlib.h>
int main(void){
    int i,j;
    int* array1 = (int*)malloc(sizeof(int)*5);
    int* array2 = (int*)calloc(sizeof(int),5);
    for(i = 0; i < 5; i++){
        printf("%p: %d\n",&array1[i],array1[i]);
    }
    printf("===================\n");
    for(j = 0; j < 5; j++){
        printf("%p: %d\n",&array2[j],array2[j]);
    }
    return 0;
}

根据此信息,前五个值必须包含垃圾值(实际上它应该看起来像随机数据),后五个值必须为零。但是当这段代码在Windows中为运行时,没有问题,但是当这段代码在Linux中为运行时,则不会出现这种情况。我认为它取决于 ASLR 或 DEP 保护,我关闭了 ASLR 并使用旧的 Linux 系统进行 DEP 保护,但结果是一样的。最后,我认为它可能依赖于 C 标准,我在编译代码时更改了 C 标准,但结果没有什么不同。请问这是什么原因。

malloc 没有用零填充数据(如您所料)。但不能保证垃圾数据不为零。所以没关系,如果您分配内存并且有时或在某些情况下看到所有字段都归零。我假设如果大小更大,或者如果您将分配,填充 smth,释放,再次分配,您将在“分配的”内存中看到“更随机”的数据。但是使用 calloc 即使在这样的操作之后你仍然会看到内存归零。

malloc 的行为是 returns 未初始化 内存。从未初始化的内存中读取是未定义的行为,这意味着任何事情都可能发生;一个足够聪明的编译器可以检测到您正在从未初始化的内存中读取数据,甚至可以优化读取并将其替换为常量值,甚至终止您的程序。

也就是说,出于安全考虑,您读取的是零,而不是内存那部分发生的任何剩余值。几年前它实际上会那样做。但后来人们意识到,这可能会泄露密钥或其他秘密,因此 Linux'(和 *BSD 的)内核的行为发生了变化,因此 memory pages are zeroed out at the first time they're mapped to a process. For Linux this behavior was introduced in Linux-2.6.33. The mmap syscall(这就是 malloc/calloc 分配器的行为在内部用于与内核对话)获得了一个新标志:

MAP_UNINITIALIZED (since Linux 2.6.33)

Don't clear anonymous pages. This flag is intended to improve performance on embedded devices. This flag is only honored if the kernel was configured with the CONFIG_MMAP_ALLOW_UNINITIALIZED option. Because of the security implications, that option is normally enabled only on embedded devices (i.e., devices where one has complete control of the contents of user memory).