1. ホーム
  2. Qt

セグメンテーションフォールト(コアダンプ)エラー共通原因まとめ

2022-02-23 21:09:19
<パス

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でコアファイルを表示する



デフォルトのコンパイルでは、Segmentation faultが発生した場合、コアクラッシュファイルが生成されませんので、gcc/g++のコンパイル時に-gオプションを追加してください。

それでもコアファイルが生成されない場合は、システムがコアファイルのサイズを0に設定している可能性があります(ulimit -a.で確認できます)。

ulimit -c unlimitedを実行すると、コアファイルのサイズが無制限になります。再度プログラムを実行すると、同じレベルのディレクトリに core.XXX ファイルが表示されるはずです。

gdb を使用します。/XXX を使って、エラーが発生した行を見ることで、gdb のコアデバッギングモードになります。

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

gdb>bt

これは一般的に、どの行のコードがエラーになっているかを確認することができ、さらに分析するために対応する変数の値も出力されます。

3 GDBによるプログラムのデバッグ



上記の作業で解決しない場合は、以下の方法でgdbを使用して一度にデバッグすることが可能です。コンパイルコマンドに-gを付けて、プログラムを再コンパイルする e.g.

gcc -lm -O3 -g file.c -o ファイル



その後、gdbコマンドを使用します。

gdbファイル



デバッグを開始します。

プログラムの次の行を実行するには next または n、xx 行目まで実行するには until xx、変数の値を出力するには print または p、xx 行目にブレークポイントを設定するには b xx、次のブレークポイントまで実行するには run または r、xx 行目でブレークポイントを解除するには d xx と入力してください。

まずプログラムを実行し、その時点でエラー行のプロンプトが表示されるようにすればよい。そして、エラー行の最初の5行に到達するまで、nextとprintを交互に実行し、エラー行変数に関連付けられた変数またはポインタの値を出力します。最後に、ルート操作に間違いがある行を見つけます。それを修正します。

参考リンク https://www.cnblogs.com/kuliuheng/p/11698378.html#_label1

コンパイルはできるが、Segment faultで実行されるプログラムがある。これは通常、ポインターエラーが原因です。しかし、コンパイルエラーのようにファイル行にプロンプトが表示されるのではなく、情報がないのです。一つの方法は、gdbのstepを使い、一歩一歩探していくことです。しかし、何万行もあるコードをステップしていくのは想像を絶するものがあります。もっといい方法があります。それがコアファイルです。



シグナル割り込みでエラーが発生したときにコアファイルを生成させたい場合は、次のようにシェルで設定する必要があります。

# コアサイズを無制限に設定する ulimit -c unlimited

#ファイルサイズを無限に設定する ulimit unlimited

コアダンプの後、gdbを使ってコアファイルの内容を表示し、コアダンプの原因となったファイル内の行を探します。

gdb [execファイル] [コアファイル]。

例: gdb . /test test.core gdbを入力した後、btコマンドでバックトレースを確認し、プログラムがどこで実行されているかを確認し、コアダンプファイル->の行を探します。

もうひとつ、自分のマシンでたくさんのアプリケーションを動かしていて、コアが生成され、どのアプリケーションが生成したのかわからない場合、次のコマンドで確認することができます:ファイルコア

少し質問です。

  1. Coreとは。

半導体がメモリの材料として使われる前、人類はメモリの材料としてコイルを使い(王安が発明)、コイルをコアと呼び、コイルで作ったメモリをコアメモリと呼んだ。現在、半導体産業が盛んになり、コアメモリを使う人はいなくなったが、多くの場合、人々はまだメモリをコアと呼んでいる。

  1. コアダンプとは。

プログラムを開発する(あるいは使用する)ときに最も恐れることの一つは、それが何らかの形でポーンしてしまうことです。システムは大丈夫でも、次に同じ問題に遭遇する可能性があります。そこでOSは、プログラムがクラッシュしたときに、私たちやデバッガが参照できるように、プログラムのメモリ内容をダンプします(現在ではたいていcoreというファイルに書き込まれます)。この動作をコアダンプと呼びます。

  1. コアダンプで生成されるファイルについて。

Core Dumpは、core.process numberなどのファイルを生成します。

  1. Coreファイルが生成されずにプログラムが停止することがあるのはなぜですか。

Linuxでは、シェルやプロセスで利用できるリソースをマークする設定があります。これを利用すると

#ulimit -a でこれらの設定を確認できます。(ulimitはbashの組み込みコマンドです)

ここにあるように、-cが表示されている場合は、コアファイルのサイズです。この値が0の場合は、コアファイルを生成することができません。なので、使うことができます。#ulimit -c 1024 または #ulimit -c unlimited でコアファイルを有効にすることができます。もし、プログラムがエラー時にコアファイルを生成した場合、Segmentation fault (core dumped)と表示されます。

  1. Core Dumpのコアダンプファイルのディレクトリと命名規則。

/proc/sys/kernel /core_uses_pid は、結果のコアファイルのファイル名に拡張子として pid を追加するかどうかを制御し、追加する場合はファイルの内容が 1、それ以外の場合は 0 になります。

このファイルは、以下のコマンドで変更することができます。

echo "1" > /proc/sys/kernel/core_uses_pid

  1. Coreファイルの使用方法。

Linuxでは、使用してください。

#gdb -c core.pid プログラム名

これでgdbのモードになります。

whereと入力すると、どの行がDownしているか、どの関数内で、誰が呼び出したか、などが示されます。

(gdb) where

またはbtと入力します。

(gdb) bt

  1. 通常のプログラムをダウンさせる方法。

#kill -s SIGSEGV pid

  1. Coreファイルの出力先を確認する。

Coredumpが格納されるディレクトリは、プロセスのカレントディレクトリで、一般的にはコマンドを発行したときにプロセスが開始されたディレクトリになります。しかし、プロセスがスクリプトによって起動された場合、スクリプトがカレントディレクトリを変更することがあり、プロセスの本当のカレントディレクトリは、スクリプトが実行されたディレクトリとは異なることになります。この場合、シンボリックリンクのターゲットである "/proc/<プロセス pid>/cwd" を確認することで、プロセスの実際のカレント・ディレクトリ・アドレスを確認することができます。システムサービスを通じて開始されたプロセスも、この方法で確認することができます。

proc/sys/kernel /core_pattern コアファイルの格納場所とファイル名の形式を制御します。

このファイルは、以下のコマンドで変更することができます。

echo "/corefile/core-%e-%p-%t" >core_pattern

コア・ファイルは、/corefile ディレクトリに一様に生成することができ、生成されるファイル名は core-command-name - pid - timestamp となります。

以下は、パラメータの一覧です。

%p - ファイル名に pid を挿入する pid を追加する

u - ファイル名に現在の uid を挿入する 現在の uid を追加する

%g - 現在の gid をファイル名に挿入します。

s - insert signal that caused the coredump into the filename コアダンプが生成される原因となったシグナルを追加してください。

%t - コレダンプが発生したUNIX時間をファイル名に挿入します コアファイルが生成されたUNIX時間を追加します

h - コレダンプが発生したホスト名をファイル名に挿入してください。

e - コレダンプの実行ファイル名を挿入し、コマンド名を追加します。

LinuxでプログラムがクラッシュしたときにCoredumpが生成されるようにするためには、以下の点に注意してください。

1つは、Coredumpが格納されるディレクトリが存在し、プロセスがそのディレクトリへの書き込みアクセス権を持っていることを確認することです。Coredumpが格納されているディレクトリは、プロセスのカレントディレクトリであり、一般的には、コマンドを発行したときにプロセスが開始されたディレクトリです。しかし、プロセスがスクリプトによって起動された場合、スクリプトがカレントディレクトリを変更することがあり、プロセスの本当のカレントディレクトリはスクリプトが実行されたディレクトリと異なることになります。この場合、"/proc/processpid>/cwd"のシンボリックリンクのターゲットを確認することで、プロセスの実際のカレントディレクトリアドレスを確認することができます。システムサービスによって開始されたプロセスも、この方法で確認することができます。

プログラムが seteuid()/setegid() を呼び出してプロセスの有効なユーザまたはグループを変更する場合、システムはデフォルトでこれらのプロセスの Coredump を生成しません。これを行う有効なユーザは常に msyql ユーザです。ユーザAとしてプログラムを実行したが、psで見るユーザがBであった場合、これらのプロセスはseteuidを呼び出していることになります。これらのプロセスにコアダンプを生成させるためには、/proc/sys/fs を変更する必要があります。

/suid_dumpable ファイルを 1 に設定します(デフォルトは通常 0)。

3つ目は、一般的にCoreファイルのサイズ制限を十分に大きく設定することと言われています。プログラムがクラッシュしたときに生成されるCoreファイルのサイズは、そのプログラムが実行されたときに占有するメモリのサイズになります。しかし、プログラムがクラッシュしたときの挙動は、普段の挙動から推定することはできない。例えば、バッファオーバーフローなどのエラーでスタックが破壊されることがあるため、変数の値がめちゃくちゃに変更され、そのサイズを使ってプログラムがメモリを要求することで、普段より多くのメモリを占有することがよくあります。そのため、プログラムが通常動作時に使用するメモリがどんなに少なくても、サイズ制限をUNLIMITEDに設定した方が、確実にCoreファイルを生成することができます。

4. 例外終了は必ずコアを生成するのですか?コアが生成されない例外はないのでしょうか?

通常の終了でない場合は、プログラムを終了させる信号があり、一部の信号はプログラムを終了させますが、コアは生成されません。

SIGHUP がプロセスを終了させる ターミナル行がハングアップする

SIGINT 処理を終了する 処理を中断する

SIGQUITは、プロセスを終了させ、COREファイルを生成します。

SIGILL CORE ファイルを作成する不正なコマンド

SIGTRAP COREファイルのトレースセルフトラップを作成します。

SIGBUS COREファイルの作成 バスエラー

SIGSEGV COREファイル作成セグメント不正エラー

SIGFPE CORE ファイル作成時の浮動小数点例外

SIGIOT COREファイルの作成 実行I/Oの自己トラップ

SIGKILL プロセスを終了させる kill プロセス

SIGPIPE プロセスの終了 読み込みプロセスのないパイプラインへの書き込み

SIGALARM プロセスの終了 タイマーが切れる

SIGTERM プロセスの終了 ソフトウェア終了信号

SIGSTOP 処理停止 ノンターミナルからの停止信号

SIGTSTP 処理停止 端末からの停止信号

SIGCONT 停止したプロセスの実行を継続するための信号を無視する

SIGURG 無視信号 I/O 緊急信号

SIGIO 無視 ディスクリプタで利用可能な信号 I/O

SIGCHLD 無視する信号 子プロセスが停止または終了したときに親プロセスに通知する

SIGTTOU 停止プロセスバックグランドプロセス書き込み端末

SIGTTIN 処理停止 バックグラウンド・プロセス 読み出し 端末

SIGXGPU 終了プロセス CPU タイムアウト

SIGXFSZ 終了プロセス ファイル長が長すぎる

SIGWINCH 無視信号 ウィンドウサイズ変更

SIGPROF プロセスの終了 タイマーを使った統計分布の時刻表示

SIGUSR1 プロセスの終了 ユーザー定義信号1

SIGUSR2 プロセスの終了 ユーザー定義信号 2

SIGVTALRM プロセスの終了 仮想タイマーを起動する

どのような状況かを確認するために、考えられるすべてのシグナルへのハンドルを設定する。

参考リンク https://blog.csdn.net/yam_killer/article/details/7970163