web-dev-qa-db-ja.com

スタックとヒープが衝突するとどうなるか

スタックとヒープが衝突するとどうなるか知りたいです。誰かがこれに遭遇した場合、彼らはシナリオを説明できますか?.

前もって感謝します。

54
mahesh

最新のOSで実行されている最新の言語では、スタックオーバーフロー(万歳!)またはmalloc()またはsbrk()またはmmap()のいずれかが発生します。ヒープを増やしてみてください。ただし、すべてのソフトウェアが最新であるとは限らないため、障害モードを見てみましょう。

  • スタックがヒープに成長すると、通常、Cコンパイラはヒープのデータ構造をサイレントに上書きし始めます。最新のOSでは、1つ以上の仮想メモリがありますガードページスタックが無期限に大きくなるのを防ぎます。ガードページのメモリ量が、少なくとも増大するプロシージャのアクティベーションレコードのサイズと同じである限り、OSはセグメンテーション違反を保証します。 MMUのないマシンでDOSを実行している場合は、おそらくうんざりしています。

  • ヒープがスタックに成長した場合、オペレーティングシステムは常に状況を認識している必要があり、ある種のシステムコールは失敗します。 malloc()の実装は、ほぼ確実に失敗に気づき、NULLを返します。その後何が起こるかはあなた次第です。

私は、OSがスタックオーバーフローを防ぐためにガードページを配置することを望んでいるコンパイラライターの意欲にいつも驚いています。もちろん、このトリックは、それぞれが独自のスタックを持つ何千ものスレッドを持ち始めるまではうまく機能します...

62
Norman Ramsey

これはプラットフォームに依存します。多くのプラットフォームでは、実際にはまったく発生しません(ヒープとスタックは異なるページに割り当てられており、2つが一致する必要はありません。

ヒープが上向きに成長し、スタックが下向きに成長するという考えは概念的なものにすぎないことに注意してください。非常に小さなシステム(CP/Mを実行していた古い8ビットマイクロなど)および一部のPICやその他のフラットメモリモデルシステム(MMU、その他の仮想メモリまたは保護されたメモリのサポートがないシステム) )次に、ヒープとスタックは実際にはこの方法で実装される可能性があります。その場合、動作は未定義になります...しかし、コードが破損したスタックの最上位のアドレスに戻ろうとするか、次のようにするとすぐにクラッシュします。ヒープのある部分から別の部分への間接ポインタまたは.。

いずれにせよ、最新の汎用ワークステーションやサーバーでは表示されません。リソースの制限に達してmalloc障害が発生するか、仮想メモリにぶつかると、最終的にシステムは「赤いスイッチを押す」という震える山にぶつかります。

42
Jim Dennis

そのような時代には、イゴン・スペングラー博士の賢明な言葉に目を向ける時が来ました。

  • エゴン・スペングラー博士:私があなたに言うのを忘れた非常に重要なことがあります。
  • ピーター・ベンクマン博士:何ですか?
  • エゴン・スペングラー博士:ヒープをスタックに衝突させないでください。
  • ピーター・ベンクマン博士:なぜですか?
  • エゴン・スペングラー博士:それは悪いことです。
  • ピーター・ベンクマン博士:私はここでの「良い/悪い」こと全体について少し曖昧です。 「悪い」とはどういう意味ですか?
  • イゴン・スペングラー博士:あなたが知っているように、すべての生命が瞬時に停止し、体内のすべての分子が光速で爆発することを想像してみてください。
  • レイ・スタンツ博士:完全なプロトン逆転!
  • ピーター・ベンクマン博士:それは悪いことです。はい。わかりました、重要な安全上のヒント。ありがとう、エゴン。
12
Paul Dixon

運が良ければ、メモリ不足例外またはスタック例外が発生します。運が悪ければ、プログラムは無効なメモリに向かい、不良メモリ例外をスローします。あなたが非常に不運な場合、プログラムは続行し、それがすべきではない何かをゴミ箱に捨て、あなたはあなたのプログラムが失敗した理由を決して知りません。

最後にもちろん、宇宙は割れるかもしれません。

6
Preet Sangha

スタック/ヒープオーバーフローが発生すると、セグメンテーション違反またはメモリ割り当てエラーが発生します。ここに例があります:

void recursiveFun ()
{
    static int i;
//  char *str= (char *)malloc (100);
    printf ("%d\t", i++);
    recursiveFun ();
// free (str);
}

上記の関数を呼び出すと、スタックが不足し、プログラムがクラッシュするとします。ここで、コメント行を削除して関数を再度呼び出すと、以前のバージョンよりも短い時間と少ない再帰でセグメンテーション違反が発生することがわかります。 [私のテスト環境では、スタックオーバーフローは最初のケースでは5237765の再帰後に発生しましたが、2番目のシナリオでは2616325の再帰後に発生しました。]

1
Sach

スタックオーバーフローエラーが発生します。または、malloc()などの新しいヒープメモリ割り当て関数が失敗します。

0
Huiguorou