web-dev-qa-db-ja.com

SIGSEGVの原因

セグメンテーション違反(SIGSEGV)の根本原因とその対処方法を知る必要があります。

31
Vaibhav

Wikipedia には他の多くのソースとともに答えがあります。

セグメンテーション違反とは、基本的にポインターで何か悪いことをしたことを意味します。これはおそらくセグメンテーション違反です:

char *c = NULL;
...
*c; // dereferencing a NULL pointer

またはこれ:

char *c = "Hello";
...
c[10] = 'z'; // out of bounds, or in this case, writing into read-only memory

または多分これ:

char *c = new char[10];
...
delete [] c;
...
c[2] = 'z'; // accessing freed memory

それぞれの場合に同じ基本原則-あなたはあなたのものではないメモリで何かをしている。

47
Chris Lutz

セグメンテーションエラーにはさまざまな原因がありますが、基本的に、メモリに誤ってアクセスしています。これは、nullポインタの逆参照、読み取り専用メモリの変更の試行、またはプロセスのメモリ空間にマップされていない場所へのポインタの使用が原因である可能性があります(つまり、数値をポインタとして使用しようとしていることを意味します) 、またはポインタを増やしすぎた)。一部のマシンでは、ポインターを介した位置合わせ不良のアクセスでも問題が発生する可能性があります-奇数アドレスがあり、そのアドレスから偶数バイトを読み取ろうとすると(代わりにSIGBUSを生成できます)。

12

無効/ヌルポインターを使用していますか?配列の境界を超えていますか?サンプルコードなしで具体的に特定するのは難しい。

基本的に、あなたはあなたのプログラムに属さないメモリにアクセスしようとしているので、OSはそれを殺します。

6
MichaelM

SIGSEGVの例を次に示します。

root@pierr-desktop:/opt/playGround# cat test.c
int main()
{
     int * p ;
     * p = 0x1234;
     return 0 ;
}
root@pierr-desktop:/opt/playGround# g++ -o test test.c  
root@pierr-desktop:/opt/playGround# ./test 
Segmentation fault

そして、これが detail です。

対処方法

  1. そもそもできるだけ避けてください。

    防御的なプログラム:assert()を使用し、NULLポインターをチェックし、バッファーオーバーフローをチェックします。

    静的分析ツールを使用して、コードを調べます。

    -Werror -Wallを使用してコードをコンパイルします。

    誰かにコードをレビューしてもらいます。

  2. それが実際に起こったとき。

    慎重にコードを調べてください。

    前回クラッシュせずに正常にコードを実行してから変更した内容を確認してください。

    クラッシュが発生した場所を知るために、gdbが呼び出しスタックを提供してくれることを願っています。


編集:ラッシュごめんなさい。そのはず *p = 0x1234; の代わりに p = 0x1234;

4
pierrotlefou

SigSegVは、プロセスがアクセスできないメモリ領域への読み書きを試みるメモリアクセス違反のシグナルを意味します。これらはCまたはC++の例外ではないため、シグナルをキャッチできません。問題を無視し、不安定なプログラムを未定義の状態で継続して実行できるシグナルハンドラを作成することは可能ですが、これは非常に悪い考えであることは明らかです。

ほとんどの場合、これはプログラムのバグが原因です。指定されたメモリアドレスは、問題のデバッグに役立ちます(ゼロに近い場合、nullポインターの逆参照、アドレスが0xadcedfeなどの場合、意図的な保護またはデバッグチェックなど)。

シグナルを「キャッチ」する方法の1つは、メインプロセスを停止せずに突然終了できる別の子プロセスで処理することです。根本的な原因を見つけて修正することは、このような回避策よりも明らかに好ましいです。

2

プログラムによって宣言されていないメモリにアクセスすると、セグメンテーション違反が発生します。これは、ポインター、つまりメモリアドレスを使用して行うことができます。または、これは、たとえば次のスタックオーバーフローが原因である可能性もあります。

void rec_func() {int q = 5; rec_func();}

int main() {rec_func();}

この呼び出しは、スタックメモリが完全にいっぱいになるまでスタックメモリを消費し続け、最終的にスタックオーバーフローが発生します。注:タイムアウトエラーが最初に発生するため、競合する質問では表示されない場合がありますが、タイムアウトが発生しない場合はsigsemvを理解するのは困難です。

1
NIKESH SINGH