noh*_*hup 9 c linux stack-overflow out-of-memory rust
我在Debian OS上运行一个带递归调用的程序.我的堆栈大小是
-s: stack size (kbytes) 8192
Run Code Online (Sandbox Code Playgroud)
据我所知,堆栈大小必须是固定的,并且必须与每次运行时必须分配给程序的相同,除非明确更改它ulimit
.
递归函数是递减给定的数字,直到达到0
.这是用Rust写的.
fn print_till_zero(x: &mut i32) {
*x -= 1;
println!("Variable is {}", *x);
while *x != 0 {
print_till_zero(x);
}
}
Run Code Online (Sandbox Code Playgroud)
并且值传递为
static mut Y: i32 = 999999999;
unsafe {
print_till_zero(&mut Y);
}
Run Code Online (Sandbox Code Playgroud)
由于分配给程序的堆栈是固定的,理论上不能改变,我每次都希望堆栈溢出的值相同,但不是,这意味着堆栈分配是可变的.
运行1:
====snip====
Variable is 999895412
Variable is 999895411
thread 'main' has overflowed its stack
fatal runtime error: stack overflow
Run Code Online (Sandbox Code Playgroud)
运行2:
====snip====
Variable is 999895352
Variable is 999895351
thread 'main' has overflowed its stack
fatal runtime error: stack overflow
Run Code Online (Sandbox Code Playgroud)
虽然差别很小但是不应该理想地导致堆栈在同一个变量上溢出?为什么它会在不同的时间发生,这意味着每次运行的堆栈大小不同?这不是Rust特有的; 在C中观察到类似的行为:
#pragma GCC push_options
#pragma GCC optimize ("O0")
#include<stdio.h>
void rec(int i){
printf("%d,",i);
rec(i-1);
fflush(stdout);
}
int main(){
setbuf(stdout,NULL);
rec(1000000);
}
#pragma GCC pop_options
Run Code Online (Sandbox Code Playgroud)
输出:
运行1:
738551,738550,[1] 7052 segmentation fault
Run Code Online (Sandbox Code Playgroud)
运行2:
738438,738437,[1] 7125 segmentation fault
Run Code Online (Sandbox Code Playgroud)
Mat*_*lia 16
最有可能的原因是ASLR.
堆栈的基址在每次运行时随机化,以使某些类型的漏洞更加困难; 在Linux上,它的粒度为16个字节(这是x86和我所知道的几乎任何其他平台上最大的对齐要求).
另一方面,x86上的页面大小(通常)为4 KB,当您触摸第一个禁止页面时,系统会检测到堆栈溢出; 这意味着您将始终首先获得部分页面(偏移量取决于ASLR),然后在系统检测到堆栈溢出之前有两个完整页面.因此,总可用堆栈大小至少是您请求的8192个字节,加上第一个部分页面,其每次运行的可用大小不同.1
归档时间: |
|
查看次数: |
280 次 |
最近记录: |