42

セグメンテーション違反またはctrl-cをキャッチするために使用するアプリケーションがあります。以下のコードを使用すると、セグメンテーション違反をキャッチできますが、ハンドラーが何度も呼び出されています。どうすればそれらを止めることができますか。参考までに、アプリケーションを終了したくありません。破損したバッファをすべて解放するように注意することができます。

出来ますか?

void SignalInit(void )
{

struct sigaction sigIntHandler;

sigIntHandler.sa_handler = mysighandler;
sigemptyset(&sigIntHandler.sa_mask);
sigIntHandler.sa_flags = 0;
sigaction(SIGINT, &sigIntHandler, NULL);
sigaction(SIGSEGV, &sigIntHandler, NULL);

}

ハンドラーは次のようになります。

void mysighandler()
{
MyfreeBuffers(); /*related to my applciation*/
}

ここでセグメンテーション障害シグナルの場合、ハンドラーが複数回呼び出されており、明らかなように、 MyfreeBuffers() は既に解放されたメモリを解放するためのエラーを返します。一度だけ解放したいのですが、それでもアプリケーションを終了したくありません。

助けてください。

4

7 に答える 7

37

などのデフォルトのアクションSIGSEGVはプロセスを終了することですが、そのハンドラーをインストールすると、デフォルトの動作をオーバーライドしてハンドラーが呼び出されます。しかし、問題は、ハンドラーが終了した後にセグメンテーション違反命令が再試行される可能性があることです。最初のセグ障害を修正するための措置を講じていない場合、再試行された命令は再び失敗し、それが何度も繰り返されます。

したがって、最初に結果となった命令を見つけて、SIGSEGVそれを修正しようとします (backtrace()ハンドラー内のようなものを呼び出して、何がうまくいかなかったのかを自分で確認できます)。

また、POSIX 標準では、

[XSI] SIGBUS、SIGFPE、SIGILL、または SIGSEGV シグナルが kill()、[RTS] sigqueue()、または raise( )。

したがって、最初にセグメンテーション違反を修正するのが理想的です。segfault のハンドラーは、根本的なエラー状態を回避するためのものではありません

したがって、最良の提案は-キャッチしないでくださいSIGSEGV。コアをダンプさせます。コアを分析します。無効なメモリ参照を修正してください。

于 2012-04-18T05:00:19.987 に答える
10

が再び起動した場合SIGSEGV、明らかな結論は、 への呼び出しが根本的な問題を修正しMyfreeBuffers();いないということです (そして、その関数が実際free()に割り当てられたメモリの一部しか実行しない場合、なぜそうなると思うのかわかりません)。

大まかに言えば、SIGSEGVアクセスできないメモリ アドレスにアクセスしようとしたときに発生します。アプリケーションを終了しない場合は、そのメモリ アドレスにアクセスできるようにするか、 で実行パスを変更する必要がありますlongjmp()

于 2012-04-18T05:28:34.403 に答える
6

の後に続行しようとしないでくださいSIG_SEGV。基本的に、アプリケーションの環境が何らかの形で破損していることを意味します。ヌル ポインターを逆参照したばかりである可能性があります。または、何らかのバグによってプログラムがスタック、ヒープ、またはポインター変数を破損させた可能性がありますが、それはわかりません。唯一の安全な方法は、プログラムを終了することです。

control-C を処理することは完全に正当です。多くのアプリケーションでそれが行われていますが、シグナル ハンドラで何を行うかを正確に注意する必要があります。再入可能でない関数を呼び出すことはできません。つまりMyFreeBuffers()、stdlibfree()関数を呼び出すと、おそらく失敗することになります。プログラムがヒープ割り当てを追跡するために使用するデータ構造を操作している最中malloc()または途中でユーザーが control-C を押した場合、信号ハンドラーでまたはを呼び出すと、ほぼ確実にヒープが破損します。free()malloc()free()

シグナルハンドラーでできる唯一の安全なことは、シグナルをキャッチしたことを示すフラグを設定することです。その後、アプリはフラグを定期的にポーリングして、何らかのアクションを実行する必要があるかどうかを判断できます。

于 2012-04-18T10:54:52.877 に答える
0

状態変数を設定し、設定されていない場合にのみメモリを解放することができます。シグナルハンドラーは毎回呼び出されますが、そのAFAIKを制御することはできません。

于 2012-04-18T05:00:11.480 に答える
0

少なくとも Linux では、 -fnon-call-exceptions オプションを使用してトリックを使用することが解決策になるようです。これにより、信号を一般的な C++ 例外に変換し、一般的な方法で処理することができます。linux3/gcc46: "-fnon-call-exceptions" を見てください。どのシグナルが命令をトラップしていますか? 例えば。

于 2016-11-14T10:47:23.400 に答える