linux下的malloc,隐式限制

Max*_*Max 4 c linux malloc

对不起,如果标题不像它应该的那样具有描述性,那么问题很难用几句话来表达.我试图通过malloc'ing找出我有多少内存,如果有效,写入该段.在某些系统上(x86_64上的所有linux),我在写入2049th mib时看到了段错误.代码是:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <sys/mman.h>

int main (int argc, char **argv) {
    void *addr;
    int megasize = 2100
    /// allocate the memory via mmap same result
    //addr = mmap ((void *) 0, (size_t) megasize << 20, PROT_READ | PROT_WRITE,
    //                                                      MAP_PRIVATE | MAP_ANONYMOUS, (int) -1, (off_t) 0);
    addr = malloc(megasize << 20);
    if (addr == MAP_FAILED) {
            fprintf (stderr, "alloc of %d megabytes failed %s\n", megasize,
            strerror (errno));
            exit (1);
    };
    printf ("got %d megabytes at %p\n", megasize, addr);
    {
            int i;
            char *p = addr;
            printf("touching the %d Mb memory:\n", megasize);
            for (i = 0; i < megasize; i++) {
                    p[i << 20] = 0;
                    putchar('.');
                    if (i%64==63) // commenting out this line i see that it really is the 2049th mb
                            printf(" #%d\n", i);
                    fflush(stdout);
            };
            putchar('\n');
    };
    /// free the memory
    munmap (addr, (size_t) megasize << 20);
    return 0;
} 
Run Code Online (Sandbox Code Playgroud)

它在某些系统上可靠地进行了段落,而在其他系统上,它可以正常工作.读取失败的系统的日志告诉我它不是oom杀手.我可以选择megasize的值,这将导致malloc失败,但那些更大.对于任何大于2gib且小于malloc为这些系统返回-1的限制,可以可靠地发生段错误.

我相信有一个限制,我没有观察到malloc没有观察到,我无法弄清楚它是什么.我尝试通过getrlimit读出一些限制,这些限制似乎与RLIMIT_AS和RLIMIT_DATA相关,但那些更大.

这是我的valgrindlog的相关部分

==29126== Warning: set address range perms: large range [0x39436000, 0xbc836000) (defined)
==29126== Invalid write of size 1
==29126==    at 0x400AAD: main (in /home/max/source/scratch/memorytest)
==29126==  Address 0xffffffffb9436000 is not stack'd, malloc'd or (recently) free'd
Run Code Online (Sandbox Code Playgroud)

谁能告诉我一个问题是什么?

alk*_*alk 8

在计数时int i,你会得到一个溢出,int这里是4个字节宽:

p[i << 20] = ...
Run Code Online (Sandbox Code Playgroud)

更改

int i;
Run Code Online (Sandbox Code Playgroud)

成为

size_t i;
Run Code Online (Sandbox Code Playgroud)

size_t 是寻址内存时的首选类型.


R..*_*R.. 5

32位int不能存储值2049 mb。您正在通过有符号整数溢出调用未定义的行为,并且碰巧得到一个负数。在大多数32位计算机上,将其添加到指针后会回绕并最终为您提供所需的地址,这是偶然的。在64位计算机上,这将为您提供一个比内存块起始位置 2047 mb的地址(或环绕在64位内存空间的顶部)。

使用正确的类型。在这里,i应该有type size_t