2012-03-02 4 views
9

だから、私はそうする:最大スタックサイズ、ulimit -s、segfault 11 - これはどのように機能しますか?

$ ulimit -s 
8192 

素晴らしい。私が理解しているように、どのプロセスのスタックセグメントも8192キロバイトを超えることはできません。今

、それに挑戦する...コンパイル

#include <stdio.h> 

void over_8k(void) { 
    char buf[1024*1024*20]; 
} 

int main(int argc, char** argv) { 
    printf("Starting .. "); 
    over_8k(); 
    printf(" finishing.\nHow did this work?\n"); 
    return 0; 
} 

。蘭問題はありません。まあこれは正しくないのですか? over_8kだけでは、20メガバイトを超えるスタックフレームが必要です。さて、この20万のバイトにアクセスしてみましょう:

#include <stdio.h> 
#include <string.h> 

void over_8k(void) { 
    char buf[1024*1024*20]; 
    memset(buf, 'A', sizeof(buf)); 
} 

int main(int argc, char** argv) { 
    printf("Starting .. "); 
    over_8k(); 
    printf(" finishing.\nHow did this work?\n"); 
    return 0; 
} 

...ドラムロール...グレート

Segmentation fault: 11 

。しかし、それは私が期待しているエラーではない?無効なメモリアクセスですか?

なぜセグメンテーションが発生し、以前にエラーが発生していませんか?おそらくover_8kへの電話で?これはどのように作動しますか?私はすべてを知りたい。

+6

私の推測:スタック割り当ては、しばしばスタックポインタの増分/減分です。それ自体はセグメンテーションされません。データにアクセスしようとすると、マップされていないメモリに入ってクラッシュします。 – Mysticial

+1

@神秘的な:まあまあ。コンパイラがアセンブリコードを提供するのは簡単です。 – maverik

+0

上記のコードをコンパイルしてテストするためにどのコンパイラとフラグを使用していますか? – Matt

答えて

9

...

私は考えることができる二つの可能性があります:

コンパイラが全体buf配列アウト最適化されています。有効に最適化して、MSVCで

は、アレイ全体が完全に最適化されており、全く割り当てられていません。したがって、スタックを使用していません。

sub rsp, 20971520 

がセグメンテーションフォールトではないだろう。

スタック割り当ては、スタック・ポインタにだけ増加/減少です。それは単なるポインタです。マッピングされていないメモリにアクセスしようとすると、セグメンテーションのみが発生します。

+1

推測#1のための+1: "コンパイラはbuf配列全体を最適化しています" – ArjunShankar

+0

推測#1第2版のコードでは、 'buf'が使用されているので、 'buf'が読み込まれていないので、割り当てと' memset'ステートメントの両方が最適化されていなければなりません。もちろん、アセンブリを見るとすぐにそのことが確認されます。 – Matt

+0

私はMSVCでテストしましたが、アセンブリはまだ最適化されていることを示しています。どうやら、 'memset()'全体をデッドコードとして認識し、すべてを取り出すことができるようです。おそらくGCCが異なるか、デフォルトの最適化レベルが高すぎるかもしれません。 – Mysticial

6

bufアレイを宣言するには、スタックポインタをインクリメントするだけです。

スタック領域の限界を超えてスタックポインタを増やしても、プログラムがクラッシュすることはありません。これは、たまたま大きな値を持つレジスタです。しかし、その領域を超えたメモリを参照すると、プログラムがクラッシュする可能性が最も高くなります。私のコメントに拡大

+0

以下の置き換えを行うことをお勧めします。増分 - >減算、限界を超えて - >外側、より大きい - >より小さい、最後から外側 - > –

+0

実際、スタックはほとんどのプラットフォームで下向きに成長しますが、原則は同じです。 –

2

GCCを使用している場合は、-fstack-checkを使用してみるとよいでしょう。this pageにいくつかのオプションがあります。

2

なぜセグメンテーションが発生しますか?

プログラムは、OSから割り当てられていないメモリロケーションにアクセスしています。メモリ位置はヒープに属しておらず、スタックに属しません。メモリ位置が何にも属していないため、エラーメッセージはSegmentation fault: 11より詳しいことはできません。

エラーが早すぎるのはなぜですか? over_8kへの呼び出しでエラーが発生しないのはなぜですか?

Cは、プログラムのパフォーマンスに重点を置いて安全でない言語です。各機能の開始時にスタックをチェックすると、すべてのCプログラムが遅くなります。

これはどのように機能しますか?

Cでは、明示的に初期化されていないすべての変数は、作成時に初期化されません。次のコード行:

char buf[1024*1024*20]; 

はスタック上bufを割り当てますが、それは割り当てられたメモリには触れていません。

3

ほとんどのオペレーティングシステムのスタックはデマンドで割り当てられます。

これは、スタックがフルサイズで作成されていないことを意味します。代わりに、スタックの現在の端を超えて各ページを初めてタッチすると自動的に拡張されます。

この場合、memset()のアクセスは20Mのスタックを割り当てようとしますが、これはスタックサイズの制限のために失敗します。ページフォールトを満たすためにメモリを割り当てることができなかった場合、エラー報告のための多くのオプションはありません。UNIXのようなシステムで実際に実行できるのは、プロセスにシグナルを送ることです。あなたの場合、これはSIGSEGVです。