ada dll を含む C++ アプリケーションをクラッシュしてもコア ダンプが生成されない
質問
ロードされた ada 共有ライブラリを含む C++ アプリケーションを取得してコア ダンプを生成するにはどうすればよいですか クラッシュするとき?
ada 共有ライブラリをロードする C++ アプリケーションがあります。ada コード内でスタック オーバーフロー エラーが発生し、コンソール出力とともにプログラムが終了します。
raised STORAGE ERROR
アプリケーションを起動する前に「ulimit -c unlimited」を発行しても、コア ダンプ ファイルは生成されません。
キルを送っても同じことが起こります シグセグブ アプリケーションに。
キルを送信します シグセグブ ada DLL を使用しない別のアプリケーションに接続すると、希望通りのコア ダンプ ファイルが生成されます。
ここでいくつかの情報が見つかりました: http://objectmix.com/ada/301203-gnat-fstack-check-does-work.html
更新しました!エイドリアンが言ったように、矛盾はありません。 -s スタック制限を設定しながら、 -c コアファイルの制限を設定します。
まだ問題は残っています。ada ライブラリを構築するときにフラグを確認しました。 fstack-チェック フラグが設定されていないため、コア ダンプが生成されるはずです。
まだ試していないのですが、なんだか不思議な感じがします。-fstack-check コンパイラ オプション + GNAT_STACK_LIMIT 変数の設定について言及していますが、同時に ulimit コマンドについても言及していますが、これは矛盾しているように思えます。コア ダンプを生成するには、「ulimit -c」を設定することが私が知っている唯一の方法です。クラッシュ時に、これが fstack-check オプションを使用していると推測される場合、キャッチ 22 が得られます。
解決
約 2 年が経った今 (クリストファーが質問したときと同じ会社でまだ働いています)、その疑問が再び提起されました。そしてついに、コアダンプが生成されない理由が理解できたように思います。
この問題は、デフォルトで一部の POSIX シグナルのシグナル ハンドラーを実装する Ada ランタイムが原因で発生します (Linux の場合:SIGABRT、SIGFPE、SIGILL、SIGSEGV、および SIGBUS)。GNAT/Linux の場合、シグナル ハンドラーが呼び出されます。 __gnat_error_handler で a-init.c, 、次のようになります。
static void
__gnat_error_handler (int sig)
{
struct Exception_Data *exception;
char *msg;
static int recurse = 0;
...
switch (sig)
{
case SIGSEGV:
if (recurse)
{
exception = &constraint_error;
msg = "SIGSEGV";
}
else
{
...
msg = "stack overflow (or erroneous memory access)";
exception = &storage_error;
}
break;
}
recurse = 0;
Raise_From_Signal_Handler (exception, msg);
}
このハンドラーは「プロセス全体」であり、プロセスのどの部分から発生したかに関係なく (Ada/C/C++ でコード化されているかどうかに関係なく)、トリガーされた信号によって呼び出されます。
呼び出されると、ハンドラーは Ada 例外を発生させ、適切な例外ハンドラーを見つけるために Ada ランタイムに任せます。そのようなハンドラーが見つからない場合 (例:SIGSEGV が C++ コードの一部によって生成されると、Ada ランタイムはフォールバックしてプロセスを終了し、単純な出力を残すだけです。 __gnat_error_handler (例えば。「スタック オーバーフロー (または誤ったメモリ アクセス)」)。
http://www2.adacore.com/gap-static/GNAT_Book/html/node25.htm
Ada ランタイムが POSIX シグナルを処理しないようにし、それを Ada 例外に変換するには、次を使用してデフォルトの動作を無効にすることができます。
プラグマ Interrupt_State (名前 => 値、状態 => SYSTEM | RUNTIME | USER);,
例えば。SIGSEGV の処理を無効にするには、次のように定義します。
Pragma Interrupt_State(SIGSEGV, SYSTEM);
Ada コード内で - SIGSEGV が発生するとシステムのデフォルト動作がトリガーされ、問題の原因を追跡できるコアダンプが生成されます。
これは、*NIX プラットフォームで Ada と C/C++ を混合するときに注意すべき非常に重要な問題だと思います。問題の原因が Ada コードにあると誤解される可能性があるからです (出力には Ada から生成された例外が示されているため) ) 問題の本当の原因が C/C++ コードにある場合...
Ada ランタイムの SIGSEGV のデフォルト処理を無効にするのはおそらく安全ですが (「予想される」エラー処理でこれを使用するまともなプログラマはいないでしょう...まあ、航空ソフトウェアなどで、本当に悪いことが起こらないようにするために何らかの「最後の手段」機能を維持する必要があるときに使用されるかもしれません..) Ada ランタイム処理を「オーバーライド」する場合は、少し注意が必要だと思います信号用。
問題の 1 つは SIGFPE シグナルである可能性があり、デフォルトで Ada Constraint_Error 例外も発生します。このタイプの例外は、Ada コードによって「予期される動作」として使用される場合があります。Pragma Interrupt_State によって SIGFPE を無効にすると、Ada コードの実行に重大な影響を及ぼし、「通常の状況」でアプリケーションがクラッシュする可能性があります。一方、C/C++ コード内のゼロによる除算は、Ada 例外処理メカニズムをトリガーします。そして、問題の原因を示す本当の痕跡が何も残らないままになります...
他のヒント
これは私には次のように見えます 本当に あなたにとって良い使い方 エイダコア サポート。その会社の外に、Gnu Ada のランタイムと C++ の間の相互作用の意味に精通している人はほとんどいないでしょう。
Ada コードをデバッグするには、すべての部分に最後の例外ハンドラーを入れて、例外スタックをダンプすることをお勧めします。ほとんどのベンダーは、通常は Ada.Exceptions.Exception_Information と Ada.Exceptions.Exception_Message に基づいて、これを行う何らかの方法を持っています。
見つけました 話し合い セキュリティの観点から(マルウェアの発見)。基本的に試すことができるシグナルは 10 個あります。 SIGSEGV
はそのうちの 1 つにすぎません。
電話するだけでできるようです sigaction(SIGSEGV, 0, SIG_DFL);
デフォルトの信号動作を復元します。