为什么我没有堆栈溢出?

编辑在你兴奋之前看到最后的重要编辑,如果你仍然好奇,这些报告为:

  • http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=696222
  • http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=696263

我一直在尝试一段代码,并惊讶地发现我没有得到堆栈溢出。 试图简化我甚至得到的东西:

#include  int main() { int i; /* 1,500,000,000 x 4 bytes = 6,000,000,000 bytes = 6GB */ int size = 1500000000; int arr[size]; for (i = 0; i < size; i++) { arr[i] = 1; } printf("first: %d\n", arr[0]); printf("last: %d\n", arr[size - 1]); return 0; } 

这使我怀疑我甚至不知道内存管理的基础知识。 我认为arr[size]应该在堆栈上轻松分配并且很容易溢出,而是它使用我所有的内存并交换并成功完成。 我错过了什么?

笔记

  • 我在64位ubuntu 12.04上运行
  • 我尝试过使用gccclang版本:

     gcc (Ubuntu/Linaro 4.6.3-1ubuntu5) 4.6.3 Ubuntu clang version 3.0-6ubuntu3 (tags/RELEASE_30/final) (based on LLVM 3.0) 
  • 我关闭了优化( -O0

  • 运行ulimit -a我得到:

     core file size (blocks, -c) 0 data seg size (kbytes, -d) unlimited scheduling priority (-e) 0 file size (blocks, -f) unlimited pending signals (-i) 29569 max locked memory (kbytes, -l) 64 max memory size (kbytes, -m) unlimited open files (-n) 1024 pipe size (512 bytes, -p) 8 POSIX message queues (bytes, -q) 819200 real-time priority (-r) 0 stack size (kbytes, -s) 8192 cpu time (seconds, -t) unlimited max user processes (-u) 29569 virtual memory (kbytes, -v) unlimited file locks (-x) unlimited 
  • 我有4GB的RAM和大约相同的交换量


 (gdb) disassemble main Dump of assembler code for function main: 0x00000000004004f4 : push %rbp 0x00000000004004f5 : mov %rsp,%rbp 0x00000000004004f8 : push %rbx 0x00000000004004f9 : sub $0x38,%rsp 0x00000000004004fd : mov %rsp,%rax 0x0000000000400500 : mov %rax,%rbx 0x0000000000400503 : movl $0x59682f00,-0x14(%rbp) 0x000000000040050a : mov -0x14(%rbp),%eax 0x000000000040050d : movslq %eax,%rdx 0x0000000000400510 : sub $0x1,%rdx 0x0000000000400514 : mov %rdx,-0x28(%rbp) 0x0000000000400518 : cltq 0x000000000040051a : shl $0x2,%rax 0x000000000040051e : lea 0xf(%rax),%rdx 0x0000000000400522 : mov $0x10,%eax 0x0000000000400527 : sub $0x1,%rax 0x000000000040052b : add %rdx,%rax 0x000000000040052e : movq $0x10,-0x38(%rbp) 0x0000000000400536 : mov $0x0,%edx 0x000000000040053b : divq -0x38(%rbp) 0x000000000040053f : imul $0x10,%rax,%rax 0x0000000000400543 : sub %rax,%rsp 0x0000000000400546 : mov %rsp,%rax 0x0000000000400549 : add $0xf,%rax 0x000000000040054d : shr $0x4,%rax 0x0000000000400551 : shl $0x4,%rax 0x0000000000400555 : mov %rax,-0x20(%rbp) 0x0000000000400559 : movl $0x0,-0x18(%rbp) 0x0000000000400560 : jmp 0x400577  0x0000000000400562 : mov -0x20(%rbp),%rax 0x0000000000400566 : mov -0x18(%rbp),%edx 0x0000000000400569 : movslq %edx,%rdx 0x000000000040056c : movl $0x1,(%rax,%rdx,4) 0x0000000000400573 : addl $0x1,-0x18(%rbp) 0x0000000000400577 : mov -0x18(%rbp),%eax 0x000000000040057a : cmp -0x14(%rbp),%eax 0x000000000040057d : jl 0x400562  0x000000000040057f : mov -0x20(%rbp),%rax 0x0000000000400583 : mov (%rax),%edx 0x0000000000400585 : mov $0x4006bc,%eax 0x000000000040058a : mov %edx,%esi 0x000000000040058c : mov %rax,%rdi 0x000000000040058f : mov $0x0,%eax ---Type  to continue, or q  to quit--- 0x0000000000400594 : callq 0x4003f0  0x0000000000400599 : mov -0x14(%rbp),%eax 0x000000000040059c : lea -0x1(%rax),%edx 0x000000000040059f : mov -0x20(%rbp),%rax 0x00000000004005a3 : movslq %edx,%rdx 0x00000000004005a6 : mov (%rax,%rdx,4),%edx 0x00000000004005a9 : mov $0x4006c7,%eax 0x00000000004005ae : mov %edx,%esi 0x00000000004005b0 : mov %rax,%rdi 0x00000000004005b3 : mov $0x0,%eax 0x00000000004005b8 : callq 0x4003f0  0x00000000004005bd : mov $0x0,%eax 0x00000000004005c2 : mov %rbx,%rsp 0x00000000004005c5 : mov -0x8(%rbp),%rbx 0x00000000004005c9 : leaveq 0x00000000004005ca : retq End of assembler dump. 

 $ pmap 2840 2840: ./a.out 0000000000400000 4K rx-- /home/gokce/play/a.out 0000000000600000 4K r---- /home/gokce/play/a.out 0000000000601000 4K rw--- /home/gokce/play/a.out 00002b572d7be000 136K rx-- /lib/x86_64-linux-gnu/ld-2.15.so 00002b572d7e0000 8K rw--- [ anon ] 00002b572d9e0000 4K r---- /lib/x86_64-linux-gnu/ld-2.15.so 00002b572d9e1000 8K rw--- /lib/x86_64-linux-gnu/ld-2.15.so 00002b572d9e3000 1748K rx-- /lib/x86_64-linux-gnu/libc-2.15.so 00002b572db98000 2044K ----- /lib/x86_64-linux-gnu/libc-2.15.so 00002b572dd97000 16K r---- /lib/x86_64-linux-gnu/libc-2.15.so 00002b572dd9b000 8K rw--- /lib/x86_64-linux-gnu/libc-2.15.so 00002b572dd9d000 28K rw--- [ anon ] 00007ffe080a2000 5859388K rw--- [ stack ] 00007fff6dbfc000 4K rx-- [ anon ] ffffffffff600000 4K rx-- [ anon ] total 5863408K 

重要编辑

我用的是一个小手写的makefile:

 build: gcc foo.c -Wall -Wextra -g run: ./a.out .SILENT: 

使用我的常用编辑器镜头来运行程序,我现在意识到它在某种程度上是相关的。 当我从控制台运行时,我得到了段错误:

 ./a.out 

但不是我跑的时候:

 make run 

那有什么关系?

重要的编辑2

当我尝试在make run运行ulimit -s时:

 build: gcc foo.c -Wall -Wextra -g run: ulimit -s .SILENT: 

它给:

 make: ulimit: Command not found make: *** [run] Error 127 

然后我意识到当我最后添加一个额外的#时它会改变:(不是评论字符吗?)

 build: gcc foo.c -Wall -Wextra -g run: ulimit -s # .SILENT: 

我明白了:

 unlimited 

我还检查了我的bash别名,没有makewhich make赋予/usr/bin/makefile /usr/bin/make给出:

 /usr/bin/make: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked (uses shared libs), for GNU/Linux 2.6.24, BuildID[sha1]=0x1d76b881b71091d 37e6653d7c8b8e19a2a414591, stripped 

正如您所期望的那样, arr显然已经被分配到堆栈中。 从pmap输出,堆栈显然增长到接近6GB:

 00007ffe080a2000 5859388K rw--- [ stack ] 

因此,问题不在于您的程序或编译器。 问题是为什么ulimit -s 8192显然没有得到执行。

从你对我的各种问题的答案,很明显, ulimit -s设置不会通过make run传播到你的程序。 这对我来说似乎很奇怪。

如果我在你的位置,我会通过系统的limits.conf以及共享和用户的bash启动文件来查看我是否能发现任何相关内容。

没有validation它,但恕我直言,这是正在发生的事情:

 int size = 1500000000; 

你在这里得到一个溢出 – 这个数字对于int来说太大了。 变量“大小”的实际值将低得多。 您的编译器实际上应该警告您。 再一次,我没有validation它,因为我太懒了。 试试这个:

 #define SIZE 1500000000ULL int arr[SIZE]; 

当然,“i