用setrlimit()设置堆栈大小,并引发堆栈溢出/段错误

在下面给出的示例中,我尝试将堆栈大小设置为1kb。

为什么现在可以在foo()为大小为8kb的堆栈分配一个整数?

 #include <stdio.h> #include <sys/resource.h> void foo(void); int main() { struct rlimit lim = {1024, 1024}; if (setrlimit(RLIMIT_STACK, &lim) == -1) return 1; foo(); return 0; } void foo() { unsigned ints[2048]; printf("foo: %u\n", ints[2047]=42); } 

Solutions Collecting From Web of "用setrlimit()设置堆栈大小,并引发堆栈溢出/段错误"

该限制是立即设置的,但仅在尝试分配新堆栈或试图增长现有堆栈时才会被检查。 内核源码的RLIMIT_STACK( 或LXR标识符搜索 )的grep应该告诉。

显然,堆栈的初始大小是文件名+ env字符串+ arg字符串加上在setup_arg_pages分配的一些额外页面(2.6.33中的20页,1,2,128 Kb,2.6.34 3 )所需要的。

综上所述:

 initial stack size = MIN(size for filename + arg strings + env strings + extra pages, MAX(size for filename + arg strings + env strings, RLIMIT_STACK)) 

哪里

 size for filename + arg strings + env strings <= MAX(ARG_MAX(32 pages), RLIMIT_STACK/4) 

此外,使用Ingo Molnar的exec-shield补丁(Fedora,Ubuntu,…)的内核还有一个额外的EXEC_STACK_BIAS “(多于2MB以覆盖随机化效果)。” ,请参阅从acct_stack_growth()调用新函数over_stack_limit() 。 [Ubuntu1] , [Ubuntu2] , [Ubuntu3] )。

我编辑了原始程序来显示这个:

 #include <stdio.h> #include <sys/resource.h> void foo(void); int main(int argc, char *argv[]) { struct rlimit lim = {1, 1}; if (argc > 1 && argv[1][0] == '-' && argv[1][8]=='l') { printf("limiting stack size\n"); if (setrlimit(RLIMIT_STACK, &lim) == -1) { printf("rlimit failed\n"); return 1; } } foo(); return 0; } void foo() { unsigned ints[32768]; printf("foo: %u\n", ints[2047]=42); } 

其结果是:

 $./rl foo: 42 $./rl -l limiting stack size Segmentation fault $ 

我认为setrlimit会移动“资源指针”,但是在exec的新副本之前不会应用新的限制。

 #include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <sys/resource.h> void foo(int chk) { unsigned ints[2048]; ints[2047] = 42; printf("foo %d: %u\n", chk, ints[2047]); } int main(int argc, char **argv) { char *newarg[] = { "argv[0]", "one", "two" }; char *newenv[] = { NULL }; struct rlimit lim; newarg[0] = argv[0]; getrlimit(RLIMIT_STACK, &lim); printf("lim: %d / %d\n", (int)lim.rlim_cur, (int)lim.rlim_max); switch (argc) { case 1: /* first call from command line */ lim.rlim_cur = 65536; lim.rlim_max = 65536; if (setrlimit(RLIMIT_STACK, &lim) == -1) return EXIT_FAILURE; newarg[2] = NULL; foo(1); execve(argv[0], newarg, newenv); break; case 2: /* second call */ lim.rlim_cur = 1024; lim.rlim_max = 1024; if (setrlimit(RLIMIT_STACK, &lim) == -1) return EXIT_FAILURE; foo(2); execve(argv[0], newarg, newenv); break; default: /* third call */ foo(3); break; } return 0; } 

和一个测试运行:

 $ ./a.out 
 lim:8388608 / -1
富1:42
 lim:65536/65536
富2:42
杀害

为什么这个过程在打印限制之前(在调用foo之前)被杀死了,我不知道。