1. ホーム
  2. C language

Linuxプログラムにおけるセグメンテーションフォールト(コアダンプ)の一般的な解決方法

2022-02-16 21:16:20

以前、v4l-testをコンパイルして実行すると、Segmentation fault (core dumped)というセグメントエラー(コアダンプ)が発生し、コードが異なるため、エラーの原因が異なり、結果として解決方法が異なるため、いろいろ検索したが良い解決方法は見つからず、ようやくあるブログでこの種の問題の一般解を見つけた、そのブログアドレス ブログアドレスは以下の通りである。

https://www.cnblogs.com/kuliuheng/p/11698378.html

1 原因

         セグメンテーションフォールト(コアダンプ)は、ほとんどの場合、不適切なメモリ操作によって発生します。Nullポインタ、ワイルドポインタ、読み書き操作、配列への境界外アクセス、定数の破損、など。この問題を回避する良い方法は、各ポインタを宣言した後にNULLに初期化することです。この問題を取り除く最良の方法は、デバッグすることです。

より詳細な原因

(1)領域外メモリアクセス

a) 誤った添え字による境界外配列アクセス
b) 文字列を検索する際、文字列が終了したかどうかを文字列のターミネータに依存しているが、文字列がターミネータを適切に使用していない
c) strcpy, strcat, sprintf, strcmp, strcasecmp などの文字列操作関数を使用して、対象の文字列を読み書きをはじく。strncpy, strlcpy, strncat, strlcat, snprintf, strncmp, strncasecmpなどの関数は、境界外への読み書きを防ぐために使用する必要があります。

(2) マルチスレッドプログラムでは、スレッドセーフでない関数を使用する。

(3) 複数のスレッドが読み書きするデータは、ロックで保護されない。

      複数のスレッドから同時にアクセスされるグローバルデータについては、ロック保護に注意を払わないと、簡単にコアダンプが発生することになる

(4) 不正なポインタ

      a) ヌルポインタの使用
      b) ポインタの変換をやみくもに使用する。メモリのセクションへのポインタは、そのメモリがもともと構造体や型、またはそのような構造体や型の配列として割り当てられたことが確かでない限り、構造体や型へのポインタに変換してはいけませんが、構造体や型にコピーしてからアクセスすべきなのは確かです。このメモリの開始アドレスがこの構造体や型にアライメントされていないと、アクセス時にバスエラーでコアダンプしやすくなるからです。

(5)スタックオーバーフロー

          大きなローカル変数は使わないでください(ローカル変数はスタック上に確保されるため)。スタックオーバーフローを起こしやすく、システムのスタックやヒープ構造が壊れて、不可解なエラーにつながる可能性があります。

2 GDBを使用してコアファイルを表示する

 1、デフォルトでコンパイルされたプログラムでは、Segmentation faultが発生してもcore crashファイルが生成されないので、gcc/g++のコンパイル時に-gオプションを追加してください。

         例: cc -O2 -Wall -Wextra -g   -c -o test_VIDIOC_ENUMSTD.o test_VIDIOC_ENUMSTD.c

2、それでもコアファイルが生成されない場合、システムがコアファイルのサイズを0に設定している可能性があります、これはulimit -a queryで確認できます。実行する ulimit -c 無制限 コマンドを実行すると、コアファイルのサイズが無制限になります。再度プログラムを実行すると、同じレベルのディレクトリにコアファイルが表示されるはずです

3,使用する gdb . /run ファイル core でエラー行の位置を確認し、gdbのコアデバッギングモードに入ることができます。

セグメンテーションフォールトとコード関数呼び出しの場所をトレースします。

(gdb) bt

(gdb)Quitで終了します。

4、分析、それは私が問題のv4l2_test.c行410にいることは明らかであり、さらにcunitコールスタックで、我々は行番号を見ることができない、それができるようにデバッグ情報を持っているようだ、現在gdb動的ぶら下げシンボルファイルにされないので、最初にかかわらず、入力のヘルプと他のコマンドは、次を学ぶためにデバッグ、終了するには、qを入力してください。

CU_register_suites関数を呼び出していますが、関数自体は間違っていないはずで、スイートから渡される引数に問題があるのかもしれません、それは以下のように引数で構築されるコードです。

CU_SuiteInfoの配列なので、ビルドするのに適した型ではない気がしますし、あとは定義されている場所にもよりますね。

ご覧の通り、TestDB.hの712で、以下のようなコードになっています。

コードを見てわかるように、構造体は6つのメンバーを持っていますが、以前のスイートは内部に4つのパラメータを持っていたので、定義に従って追加を修正するだけです。

変更後に再コンパイルすれば、実行されます。