4

関数 A() から関数 B() への呼び出し中に、B() は 100 文字の配列を割り当て、101 文字の文字列で 1 回、110 文字の文字列で 1 回など、数回入力します。これは明らかな間違いです。

その後、関数 A() がまったく関係のない int 変数 i にアクセスしようとすると、セグメンテーション違反が発生します。

バッファ オーバーランが発生する理由は理解できましたが、この整数にアクセスするとセグメンテーション エラーが発生するのはなぜですか? 単純にガベージ データを取得しないのはなぜですか?

4

5 に答える 5

14

バッファオーバーランは、スタックに以前に保存されたバージョンのフレームポインタを破壊する可能性があります。関数が戻ると、この破損したバージョンがフレームポインタレジスタにロードされ、説明した動作が発生します。

ウィキペディアのページには、図と定義が含まれています。

于 2009-12-03T23:22:12.607 に答える
5

A()呼び出すとB()、B のプリアンブル命令は、A のフレーム ポインター (A がローカル変数を保持するスタック上の場所) を保存してから、B 自身のフレーム ポインターに置き換えます。次のようになります。

スタック フレーム

B がそのローカル変数をオーバーランすると、フレーム ポインターに再ロードされる値が台無しになります。これはフレーム ポインタの値としてゴミなので、A のローカル変数はすべて破棄されます。さらに悪いことに、ローカル変数への将来の書き込みは、他の誰かに属するメモリをいじっています。

于 2009-12-03T23:29:38.890 に答える
3

あなたの説明から最も可能性の高い説明は、B のオーバーランが A のスタックに保存されたフレーム ポインターを破損するということです。したがって、B が戻った後、A はそのフレーム ポインターにガベージがあり、ローカル変数にアクセスしようとするとクラッシュします。

于 2009-12-03T23:27:57.583 に答える
0

ポインタを介してiにアクセスしている場合、問題はポインタがゴミであるということです。

于 2009-12-03T23:21:11.017 に答える
0

nul 終端文字に十分なメモリと 1 を割り当てることを覚えておくことが重要です (賢明な読者はこの nul を指摘するでしょう。これには主に理由があります - 'l' が 1 つある nul は'\0'[Software Monkey さん、指摘してくれてありがとう。エラー!]、2 つの 'l' を持つ null は何も指していないポインターです)。

セグフォルトがどのように発生するかの例を次に示します

int main(int argc, char **argv){
    int *x = NULL;
    *x = 5;
    //ブーム
}

x はポインターであり、null に設定されているため、ポインターを逆参照して値を代入しようとします。セグメンテーション違反を生成する保証された方法。

シグナルハンドラをセットアップして SIGSEGV をトラップし、シグナルハンドラ内で次のようなプロセスを呼び出すことにより、実際にセグフォルトをトラップしてスタックトレースを取得できるという古いトリックが利用できます。これは UNIX 環境でより一般的です。

char buf[250];
buf[0] = '\0';
sprintf(buf, "gdb -a %d | where > mysegfault.txt", getpid());
システム(buf);

これにより、現在実行中の C プログラムがアタッチされ、デバッガーにシェルが実行され、デバッガーにアタッチされます。そのwhere一部には、セグ フォールトの原因となった問題のある行のスタック トレースが表示され、出力が現在のディレクトリ内のファイルにリダイレクトされます。

注: これは、インストールに応じて定義された実装です。AIX では、gnu デバッガーが存在するため、これは機能します。マイレージは異なる場合があります。

これがお役に立てば幸いです。よろしくお願いします、トム。

于 2009-12-03T23:52:43.150 に答える