web-dev-qa-db-ja.com

プロセスがいつSIGABRT(シグナル6)を受け取るのですか?

C++でプロセスがSIGABRTを取得するシナリオは何ですか?このシグナルは常にプロセス内から来るのですか、それともあるプロセスから別のプロセスへ送信されるのですか?

このシグナルを送信しているプロセスを特定する方法はありますか?

174
Shree

abort()は呼び出しプロセスにSIGABRTシグナルを送ります。これはabort()が基本的に機能する方法です。

abort()は、通常、内部エラーまたは深刻な破損した制約を検出するライブラリ関数によって呼び出されます。たとえば、malloc()は、その内部構造がヒープオーバーフローによって破損した場合にabort()を呼び出します。

166

kill(2)インターフェースを使用して、任意のシグナルを任意のプロセスに送信できます。

kill -SIGABRT 30823

30823は私が始めたdashプロセスだったので、殺したいプロセスを簡単に見つけることができました。

$ /bin/dash
$ Aborted

Abortedの出力は、明らかにdashがSIGABRTをレポートする方法です。

kill(2)を使用して任意のプロセスに直接送信することも、プロセスがassert(3)abort(3)、またはraise(3)を介して自身にシグナルを送信することもできます。

49
sarnold

SIGABRTは、重大なエラーが発生した場合に、プログラムを中止するためにlibcや他のライブラリによって一般的に使用されています。たとえば、glibcは、ダブルフリーまたはその他のヒープ破損が検出された場合にSIGABRTを送信します。

また、ほとんどのassertの実装では、アサートが失敗した場合にSIGABRTを使用します。

さらに、SIGABRTは、他のシグナルと同様に他のプロセスからも送信できます。もちろん、送信プロセスは同じユーザーまたはrootとして実行する必要があります。

46
IanH

通常、メモリ割り当てに問題があると発生します。

私のプログラムが負のサイズの配列を割り当てようとしていたときに私は起こりました。

16
Mig

C++の場合にはもう一つの単純な原因があります。

std::thread::~thread{
    if((joinable ())
        std::terminate ();
}

すなわち、スレッドのスコープは終了しましたが、どちらかを呼び出すのを忘れていました

thread::join();

または

thread::detach();
10
Sudip Bhattarai

GNU libcは、abort()を呼び出す前に致命的な状況に関する情報を/dev/ttyに出力します(これがSIGABRTをトリガーします)。メッセージを表示するttyがないため、メッセージが失われる可能性があります。

/ dev/ttyの代わりにstderrに書き込むようlibcをリダイレクトすることについての私の投稿を見てください。

/ dev/ttyからリダイレクトするlibcエラーメッセージをキャッチ

6
Mark Lakata

プロセスがSIGABRTを自分自身から取得する場合:Hrvojeは、アボートを生成するctorから呼び出される埋め込みの純粋仮想について言及しました。この例を再作成しました。ここでdが構築されるとき、それは最初にその基本クラスA ctorを呼び出し、そしてそれ自身への内側のポインタを渡す。 dはまだ構築されていないので、テーブルが有効なポインタで埋められる前に、A ctorは純粋仮想メソッドを呼び出します。

#include<iostream>
using namespace std;
class A {
public:
 A(A *pa){pa->f();}
 virtual void f()=0;
};
class D : public A {
public:
 D():A(this){}
 virtual void f() {cout<<"D::f\n";}
};
int main(){
 D d;
 A *pa = &d;
 pa->f();
 return 0;
}

g ++ -o aa aa.cppをコンパイルしてください。

ulimit -c無制限

実行:./aa

pure virtual method called
terminate called without an active exception
Aborted (core dumped)

コアファイルをすぐに確認し、SIGABRTが実際に呼び出されたことを確認します。

gdb aa core

regsを参照してください。

i r
rdx            0x6      6
rsi            0x69a    1690
rdi            0x69a    1690
rip            0x7feae3170c37

チェックコード:

災害0x7feae3170c37

mov    $0xea,%eax  = 234  <- this is the kill syscall, sends signal to process
syscall   <-----

http://blog.rchapman.org/posts/Linux_System_Call_Table_for_x86_64/

234 sys_tgkill pid_t tgid pid_t pid int sig = 6 = SIGABRT

:)

3

私の場合は、配列の長さに等しいインデックスで配列に入力されたためです。

string x[5];

for(int i=1; i<=5; i++){

    cin>>x[i];

}

存在しないx [5]がアクセスされています。

1
anonymous