linux下的c-malloc,隐式限制



很抱歉,如果标题没有达到应有的描述性,那么这个问题很难用几个词来表达。我正试图通过malloc'ing来找出我有多少内存可用,如果有效的话,就写到那个片段。在某些系统(x86_64上的所有linux)上,我在写入2049th mib时看到segfault。代码为:

#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 %sn", megasize,
strerror (errno));
exit (1);
};
printf ("got %d megabytes at %pn", 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(" #%dn", i);
fflush(stdout);
};
putchar('n');
};
/// free the memory
munmap (addr, (size_t) megasize << 20);
return 0;
} 

它在某些系统上可靠地分段故障,而在其他系统上运行良好。读取失败系统的日志告诉我它不是oom杀手。我可以选择一些会导致malloc失败的megasize值,但这些值更大。对于任何大于2gib且小于malloc为这些系统返回-1的限制的大小,segfault都会可靠地发生。

我相信我达到了一个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

有人能告诉我问题出在哪里吗?

通过int i计数时会出现溢出,因为此处int为4字节宽:

p[i << 20] = ...

更改

int i;

成为

size_t i;

size_t是寻址存储器时的首选类型。

32位int无法存储值2049mb。您正在通过有符号整数溢出调用未定义的行为,并且碰巧得到了一个负数。在大多数32位机器上,当添加到一个指针上时,指针会自动返回并最终为您提供所需的地址,这是意外的。在64位机器上,这会为您提供一个地址,该地址位于内存块起始位置下方约2047mb(或位于64位内存空间的顶部)。

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

相关内容

  • 没有找到相关文章

最新更新