C++でプロセスがSIGABRTを取得するシナリオは何ですか?このシグナルは常にプロセス内から来るのですか、それともあるプロセスから別のプロセスへ送信されるのですか?
このシグナルを送信しているプロセスを特定する方法はありますか?
abort()
は呼び出しプロセスにSIGABRT
シグナルを送ります。これはabort()
が基本的に機能する方法です。
abort()
は、通常、内部エラーまたは深刻な破損した制約を検出するライブラリ関数によって呼び出されます。たとえば、malloc()
は、その内部構造がヒープオーバーフローによって破損した場合にabort()
を呼び出します。
kill(2)
インターフェースを使用して、任意のシグナルを任意のプロセスに送信できます。
kill -SIGABRT 30823
30823は私が始めたdash
プロセスだったので、殺したいプロセスを簡単に見つけることができました。
$ /bin/dash
$ Aborted
Aborted
の出力は、明らかにdash
がSIGABRTをレポートする方法です。
kill(2)
を使用して任意のプロセスに直接送信することも、プロセスがassert(3)
、abort(3)
、またはraise(3)
を介して自身にシグナルを送信することもできます。
SIGABRT
は、重大なエラーが発生した場合に、プログラムを中止するためにlibcや他のライブラリによって一般的に使用されています。たとえば、glibcは、ダブルフリーまたはその他のヒープ破損が検出された場合にSIGABRT
を送信します。
また、ほとんどのassert
の実装では、アサートが失敗した場合にSIGABRT
を使用します。
さらに、SIGABRT
は、他のシグナルと同様に他のプロセスからも送信できます。もちろん、送信プロセスは同じユーザーまたはrootとして実行する必要があります。
通常、メモリ割り当てに問題があると発生します。
私のプログラムが負のサイズの配列を割り当てようとしていたときに私は起こりました。
C++の場合にはもう一つの単純な原因があります。
std::thread::~thread{
if((joinable ())
std::terminate ();
}
すなわち、スレッドのスコープは終了しましたが、どちらかを呼び出すのを忘れていました
thread::join();
または
thread::detach();
GNU libcは、abort()
を呼び出す前に致命的な状況に関する情報を/dev/tty
に出力します(これがSIGABRT
をトリガーします)。メッセージを表示するttyがないため、メッセージが失われる可能性があります。
/ dev/ttyの代わりにstderrに書き込むようlibcをリダイレクトすることについての私の投稿を見てください。
プロセスが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
:)
私の場合は、配列の長さに等しいインデックスで配列に入力されたためです。
string x[5];
for(int i=1; i<=5; i++){
cin>>x[i];
}
存在しないx [5]がアクセスされています。