为什么我没有堆栈溢出?
编辑在你兴奋之前看到最后的重要编辑,如果你仍然好奇,这些报告为:
- 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上运行
-
我尝试过使用
gcc
和clang
版本: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别名,没有make
。 which make
赋予/usr/bin/make
和file /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