Linuxでは、スタック割り当てはどのように機能しますか?

Linuxでは、スタック割り当てはどのように機能しますか?

オペレーティングシステムは、スタックまたはその他のアイテム用に固定量の有効仮想スペースを予約しますか?大きなローカル変数を使用するだけでスタックオーバーフローを生成できますか?

私は私の仮説をテストするために小さなCプログラムを書いた。 X86-64 CentOS 6.5で動作します。

#include <string.h>
#include <stdio.h>
int main()
{
    int n = 10240 * 1024;
    char a[n];
    memset(a, 'x', n);
    printf("%x\n%x\n", &a[0], &a[n-1]);
    getchar();
    return 0;
}

プログラムを実行する&a[0] = f0ceabe0&a[n-1] = f16eabdf

proc マップはスタックを示しています。7ffff0cea000-7ffff16ec000. (10248 * 1024B)

それでは増やそうとします。n = 11240 * 1024

プログラムを実行する&a[0] = b6b36690&a[n-1] = b763068f

proc マップはスタックを示しています。7fffb6b35000-7fffb7633000. (11256 * 1024B)

ulimit -sマイコンピュータから印刷してください10240

ご覧のとおり、どちらの場合もスタックサイズがulimit -s指定されたサイズより大きいです。そして、ローカル変数が大きくなるとスタックも大きくなります。スタックの上部は3〜5kBほど少ない&a[0](私が知っている限り、赤い領域は128Bです)。

では、このスタックマップはどのように割り当てられますか?

ベストアンサー1

スタックメモリ制限が割り当てられていないようです(とにかく無限にスタックすることはできません)。https://www.kernel.org/doc/Documentation/vm/overcommit-accounting説明する:

C言語スタックは暗黙のmremapを介して増加します。絶対的な保証を望んでエッジの近くに実行するには、必要と思われる最大サイズにスタックをマッピングする必要があります。一般的なスタック使用の場合、これは重要ではありませんが、実際に興味がある場合は極端なケースです。

ただし、スタックマッピングはコンパイラのターゲットになります(オプションがある場合)。

編集:x84_64 Debianシステムでいくつかのテストを実行した後(Stack Overflowに従ってstrace)、システムコールなしでスタックが大きくなることがわかりました。したがって、これはカーネルがプロセスで明示的mmapに成長せずに自動的に成長することを意味します(上記では「暗黙的に」という意味)。mremap

これを確認する詳細を見つけるのは難しいです。私はお勧めしますLinux仮想メモリマネージャについてメルゴーマ​​ンの地音。私の考えに対する答えはセクション4.6.1にあります。ページエラー処理、例外は、「地域は無効ですが、拡張可能領域(スタックなど)の横にあります。」とそのアクションは、「領域の拡張とページの割り当て」です。 D.5.2も参照してください。拡張スタック

Linuxメモリ管理に関するその他の参考資料(スタックにはほとんどありません):

編集2:この実装には欠点があります。極端な場合、スタックが制限より大きい場合でも、スタックヒープの衝突が検出されない可能性があります。これは、スタック内の変数への書き込みが割り当てられたヒープメモリで終了する可能性があるためです。この場合、ページエラーは発生せず、カーネルはスタックを拡張する必要があることはわかりません。ディスカッションの私の例を参照してください。GNU/Linuxでの自動スタックの競合私はgcc-helpのリストから始めました。これを防ぐには、コンパイラは関数が呼び出されたときにいくつかのコードを追加する必要があります。これはGCCを介して行うことができます-fstack-check(詳細については、Ian Lance Taylorの回答とGCCのマニュアルページを参照)。

おすすめ記事