2017-03-24 5 views
10

私はDebian OS上で再帰呼び出しを持つプログラムを実行しています。私のスタックサイズは、私の知る限り学んだように、スタックサイズが固定されている必要があり固定量ではなく、実行ごとにスタック使用量が異なると、スタックオーバーフローが発生するのはなぜですか?

-s: stack size (kbytes)    8192 

であり、それが明示的にulimitで変更されない限り、すべての実行時にプログラムに割り当てられなければならないことと同じでなければなりません。

再帰関数は、0に達するまで、与えられた数値を減らします。これはRustに書かれています。

fn print_till_zero(x: &mut i32) { 
    *x -= 1; 
    println!("Variable is {}", *x); 
    while *x != 0 { 
     print_till_zero(x); 
    } 
} 

と値がプログラムに割り当てられたスタックが固定されているので

static mut Y: i32 = 999999999; 
unsafe { 
    print_till_zero(&mut Y); 
} 

として渡され、理論的に変化してはならない、私は同じ値で、スタックオーバーフローを毎回期待していたが、そうではありません。つまり、スタック割り当ては可変です。

ラン1:

====snip==== 
Variable is 999895412 
Variable is 999895411 

thread 'main' has overflowed its stack 
fatal runtime error: stack overflow 

ラン2:

====snip==== 
Variable is 999895352 
Variable is 999895351 

thread 'main' has overflowed its stack 
fatal runtime error: stack overflow 

差は微妙であるが、それは同じ変数でスタックオーバーフローを引き起こす理想的であるべきではありませんか?異なる時間に何が起こっているのですが、実行ごとに異なるスタックサイズを意味するのでしょうか?これは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 

出力:

ラン1:

738551,738550,[1] 7052 segmentation fault 

ラン2:

738438,738437,[1] 7125 segmentation fault 
+6

スタックオーバーフローは、ページ違反時にのみ発生します。スタックポインタがアンロードされた/未所有のページに実行されたときです。スタックの開始位置は正確なページ境界である必要はなく、プログラムがロードされる場所に依存するので、オーバーフロー条件(ページフォールト)のトリガーは異なります。 –

+1

[this](http://stackoverflow.com/questions/31180563/why-are-stackoverflow-errors-chaotic)も同様ですか? – Art

+0

@RichardCrittenしたがって、割り当てられたスタックサイズ外のページは、所有されていないページの権利でなければなりません。私が間違っているなら、私を修正してください。 – nohup

答えて

16

おそらくこれはASLRによるものです。

スタックのベースアドレスは、実行ごとにランダム化され、特定の種類の攻撃をより困難にします。 Linuxの場合、これはhas a granularity of 16 bytesです(これは、x86と私が知っている他のほとんどのプラットフォームでの最大の整合要件です)。

一方、the page size is (normally) 4 KB on x86があり、最初の禁止ページをタッチするとスタックオーバーフローが検出されます。これは、システムがスタックのオーバーフローを検出する前に、部分ページを最初に(オフセットはASLRに依存する)利用可能にしてから、フルページを2つ利用できることを意味します。したがって、使用可能なスタックの合計サイズは、少なくとも要求された8192バイトと、実行ごとに使用可能なサイズが異なる最初の部分ページです。オフセットがゼロでない "通常" の場合に


  1. すべてこの;非常に幸運で、ランダムオフセットがゼロの場合、おそらく正確に2ページが得られます。
+0

x86 AFAIKでは、実際には16バイトが最も制限の厳しいアラインメント要件です。 –

+0

申し訳ありませんが、誤ってコメントを削除しましたので、ここに再度追加します。私は、スタックがランダム化されている場合、効率的なアクセスのためにページに整列させるべきではないかと尋ねていました。更新していただきありがとうございます。 – nohup

+1

最も制限の厳しいデータ型に対してのみ整列する必要があります。 –

関連する問題