プロセスがC++でSIGABRTを取得するシナリオは何ですか?この信号は常にプロセス内から送信されますか、それともこの信号を1つのプロセスから別のプロセスに送信できますか?
このシグナルを送信しているプロセスを特定する方法はありますか?
abort()
呼び出しプロセスにSIGABRT
シグナルを送信します。これがabort()
基本的に機能する方法です。
abort()
通常、内部エラーまたは深刻に壊れた制約を検出するライブラリ関数によって呼び出されます。たとえば、その内部構造がヒープオーバーフローによって損傷した場合malloc()
に呼び出します。abort()
SIGABRT
重大なエラーが発生した場合にプログラムを中止するために、libcやその他のライブラリで一般的に使用されます。たとえば、glibcSIGABRT
は、ダブルフリーまたはその他のヒープ破損が検出された場合にを送信します。
また、ほとんどの実装では、アサートが失敗した場合にassert
利用します。SIGABRT
さらに、SIGABRT
他の信号と同様に、他のプロセスから送信することもできます。もちろん、送信プロセスは同じユーザーまたはルートとして実行する必要があります。
kill(2)
インターフェイスを使用して、任意のプロセスに任意のシグナルを送信できます。
kill -SIGABRT 30823
30823はdash
私が始めたプロセスだったので、殺したいプロセスを簡単に見つけることができました。
$ /bin/dash
$ Aborted
Aborted
出力は明らかにdash
SIGABRTを報告する方法です。
を使用して任意のプロセスに直接送信できます。または、プロセスは、、、またはkill(2)
を介してシグナルを自身に送信できます。assert(3)
abort(3)
raise(3)
これは通常、メモリ割り当てに問題がある場合に発生します。
私のプログラムが負のサイズの配列を割り当てようとしたときに、それが起こりました。
C ++の場合、もう1つの単純な原因があります。
std::thread::~thread{
if((joinable ())
std::terminate ();
}
つまり、スレッドのスコープは終了しましたが、どちらかを呼び出すのを忘れました
thread::join();
また
thread::detach();
GNU libcは/dev/tty
、呼び出す前にいくつかの致命的な状態に関する情報を出力しますabort()
(これによりトリガーされます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
チェックコード:
disas 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]にアクセスしています。
競技プログラミング(cp)の観点から答えますが、他のドメインにも当てはまります。
cpを実行している間、制約は非常に大きくなります。
例N, M, Q
:。などの変数について質問がありました1 ≤ N, M, Q < 10^5
。
私が犯した間違いは、サイズの2D整数配列を宣言し、10000 x 10000
Codechefでのエラーにほぼ2日間C++
苦労したことでした。SIGABRT
さて、計算すると:
整数の一般的なサイズ:4バイト
配列内のセルの数:10000 x 10000
合計サイズ(バイト単位):400000000バイト= 4 *10^8≈400MB
このような質問に対するあなたの解決策は、このサイズを許容できるので、あなたのPC(常にではない)で機能します。
ただし、コーディングサイト(オンライン審査員)のリソースは数KBに制限されています。
したがって、SIGABRT
エラーおよび他のそのようなエラー。
結論:
このような質問では、配列やベクトル、またはこのサイズの他のDSを宣言するべきではありませんが、私たちのタスクは、アルゴリズムを効率的にして、それらがなくても(DS)、またはメモリが少なくても機能するようにすることです。
PS:このエラーには他の理由があるかもしれません。上記はそのうちの1つでした。
「@sarnold」が適切に指摘しているように、どのプロセスも他のプロセスにシグナルを送信できるため、1つのプロセスが他のプロセスにSIGABORTを送信できます。その場合、受信プロセスは、メモリなど、または他の誰かが「一律に」持っている場合は、それに送信します。
私が働いていたシステムの1つには、ハートビートを与えることによってプロセスが何らかのタスクから出ているかどうかを実際に検出するデッドロック検出器が1つあります。そうでない場合は、プロセスがデッドロック状態にあることを宣言し、SIGABORTを送信します。
尋ねられた質問を参照して、この見通しを共有したかっただけです。
最初の質問について:What are the scenarios where a process gets a SIGABRT in C++?
C ++プログラムが自動的に中止される2つの特殊なケースを考えることができます-直接呼び出すstd::abort()
かstd::terminate()
:
1つ:例外の処理中に例外をスローします。
try {
throw "abc";
}
catch (...) {
throw "def"; // abort here
}
2:外部に伝播しようとするキャッチされない例外main()
。
int main(int argc, char** argv)
{
throw "abc"; // abort here
}
C ++の専門家は、おそらくもっと特殊なケースに名前を付けることができます。
これらのリファレンスページにも多くの良い情報があります:
Androidネイティブコードの場合、 https: //source.android.com/devices/tech/debug/native-crashに従ってabortが呼び出される理由は次のとおりです。
中止は意図的なものであるため興味深いものです。中止する方法はたくさんありますが(abort(3)の呼び出し、 assert(3)の失敗、Android固有の致命的なログタイプの1つを使用するなど)、すべて中止の呼び出しが含まれます。