1. ホーム
  2. Qt

linuxのセグメンテーション障害

2022-02-16 10:22:57

1. シェルで Segmentation fault という文字列を表示したのは誰ですか?
この文字列は、実際には現在エラーになっているプロセスでもなく、カーネルでもなく、bash (または他のシェル) が出力します。bash のソースコードの WAITPID (-1, &status, 0)) ステートメントをご覧ください。そのため、自分が書いたプログラムで子プロセスの待ちを行わなかったり、子プロセスの終了シグナルをキャッチしたりすると、たとえセグメントエラーであっても、以下のプログラムのようにメッセージが出力されず、プログラムが静かに終了してしまうのです。
int main(int argc, char **argv)
{ <未定義
        if (fork() == 0){ <未定義
            int *ad = (int *)0;
            *ad = 1234。
        }
}
linuxのカーネルや標準ライブラリは、このような深刻なセグメントエラーも処理しないので、その仕組みやポリシー分離の本質を見るには十分です。ユーザーが自分で処理し、親プロセスが興味を持てば、とにかく親プロセスに通知して処理させるのです。カーネルと基礎となるライブラリは、プロセス自体がそれを処理しない場合は、デフォルトの処理、およびこのデフォルトの処理は、エラープロセスを終了し、それがしたい場合は、親プロセスですその後、親プロセスが何かをしたい場合は、それはプロセスを終了し、ステータスから情報を得るために待つことができます。
2. セグメントエラー信号はキャプチャ可能であり、一度キャプチャしてしまえば、あとは挙動が任意であり、キャプチャフックを書いた奴しか知らない。
3. 3. セグメントエラーのデバッグ方法:コアファイルを生成し、gdb proname corename とタイプして where/bt
4. セグメントエラーは時に有用です。バックトレースやbacktrace_symbols関数を理解していない場合、例えば、非常に大きなコードの中で特定の引数で呼び出された関数がある場合、どのようにしてその関数を知ることができますか?
void test(char *name, char *value, ...)
{ <未定義
    ...
}
名前が"abc"だと、まさにこんな感じでtestを呼び出すのかがわからないですよね。
void test(char *name, char *value, ...)
{ <未定義
    if (!strcmp(name, "abc")) { <未定義
        int *a = (int *)0;
        *a = 1234;
    }
    ...
}
あとはコアファイルをgdbでデバッグするだけです。
5. 時々、セグメントエラーが変になることがあります。これは、ヘッダーファイルのバージョン違いや接続ライブラリの間違いによるバイナリの非互換性など、コンパイルの問題が原因の可能性が高く、ヘッダーファイルを整理してライブラリが正しくマッチングした後に、きれいに再コンパイルするとよいでしょう。