web-dev-qa-db-ja.com

エラー:longjmpは初期化されていないスタックフレームを引き起こします

Dbus上にバスを作成するサーバーアプリケーションがあり、数分間実行した後、これまでに見たことのないエラーが発生しました。何が悪いのか考えましたか?

*** longjmp causes uninitialized stack frame ***: /home/user/Workspace/DBus_Server/Debug/DBus_Server terminated
======= Backtrace: =========
/lib/x86_64-linux-gnu/libc.so.6(__fortify_fail+0x37)[0x7f8d8911c7f7]
/lib/x86_64-linux-gnu/libc.so.6(+0xf8789)[0x7f8d8911c789]
/lib/x86_64-linux-gnu/libc.so.6(__longjmp_chk+0x33)[0x7f8d8911c6f3]
/usr/lib/x86_64-linux-gnu/libcurl-nss.so.4(+0xd795)[0x7f8d88272795]
/lib/x86_64-linux-gnu/libc.so.6(+0x36420)[0x7f8d8905a420]
/lib/x86_64-linux-gnu/libc.so.6(__poll+0x53)[0x7f8d890f9773]
/usr/lib/libdbus-c++-1.so.0(_ZN4DBus15DefaultMainLoop8dispatchEv+0x161)[0x7f8d89b6b481]
/usr/lib/libdbus-c++-1.so.0(_ZN4DBus13BusDispatcher5enterEv+0x63)[0x7f8d89b6c293]
/home/user/Workspace/DBus_Server/Debug/DBus_Server[0x401333]
/lib/x86_64-linux-gnu/libc.so.6(__libc_start_main+0xed)[0x7f8d8904530d]
/home/user/Workspace/DBus_Server/Debug/DBus_Server[0x4011c9]
22
Tobi Weißhaar

私は同じ問題に遭遇しました。上記のように、これはカールバグです。問題に関する入手可能なすべての情報をまとめるために、ここに回答を載せると思いました。

から Red Hatバグレポート

非同期リゾルバーライブラリなしでビルドされたlibcurlは、alarm()を使用してDNSルックアップをタイムアウトします。タイムアウトが発生すると、libcurlはsigsetjmpを使用してシグナルハンドラーからライブラリにジャンプして戻ります。これにより、libcurlはシグナルハンドラー内で実行を継続します。これは移植性がなく、一部のプラットフォームで問題を引き起こす可能性があります。この問題に関する議論は http://curl.haxx.se/mail/lib-2008-09/0197.html で入手できます。

「一部のプラットフォームでの問題」は、少なくとも最新のLinuxシステムでのクラッシュを指しているようです。いくつかのより深い技術的な詳細は、上記の引用からのリンクにあります:

Libcurlが現在SIGALRMシグナルを処理する方法に問題があります。 SIGALRMのハンドラーをインストールして、同期DNS解決を指定された時間後に強制的にタイムアウトさせます。これは、場合によってはそのような解決を中止する唯一の方法です。 DNS解決が行われる直前に、longjmpポインターが初期化されるため、シグナルがシグナルハンドラーに入ると、siglongjmpが実行され、その保存された場所から制御が続行され、関数はエラーコードを返します。

問題は、以下のすべての制御フローがシグナルハンドラー内で効果的に実行されることです。この間、libcurlが非同期ハンドラーの安全でない関数(signal(7)を参照)を呼び出す可能性があるだけでなく、絶対に何でも呼び出すことができるユーザーコールバック関数を呼び出す可能性があります。実際、siglongjmp()自体は非同期セーフ関数のPOSIXリストに含まれていません。これが、libcurlシグナルハンドラーの呼び出しのすべてです。

この問題を解決するには、libcurlをビルドしたかどうか、またはディストリビューションまたはシステム管理者から提供されたもので立ち往生しているかどうかに応じて、いくつかの方法があります。

  • Libcurlを再構築できない場合は、使用するすべてのcurlハンドルでcurl_easy_setopt(curl, CURLOPT_NOSIGNAL, 1)を呼び出すことができます。 CURLOPT_NOSIGNALノートのドキュメント:

    長く渡す。 1の場合、libcurlは、シグナルハンドラーをインストールする関数や、シグナルをプロセスに送信する関数を使用しません。このオプションは主に、マルチスレッドUNIXアプリケーションがシグナルを取得するリスクなしにすべてのタイムアウトオプションなどを設定/使用できるようにするためにあります。 (7.10で追加)

    このオプションが設定されていて、libcurlが標準の名前リゾルバーでビルドされている場合、名前の解決が行われている間はタイムアウトは発生しません。非同期DNSルックアップを有効にするためにc-aresサポートを使用してlibcurlを構築することを検討してください。これにより、シグナルなしで名前解決の適切なタイムアウトが有効になります。

    ほとんどの場合、DNSタイムアウトが望ましいのは明らかなので、これは完全な修正ではありません。システムでlibcurlを再構築する機能がある場合は、次のことができます...

  • c-ares と呼ばれる非同期DNSリゾルバーライブラリがあり、curlは名前解決に使用できます。このライブラリを使用することが問題の好ましい解決策です(そして、ほとんどのLinuxパッケージャがこれを理解していると思います)。 c-aresサポートを有効にするには、最初にライブラリをビルドしてインストールし、ビルドする前に--enable-aresフラグをcurlのconfigureスクリプトに渡します。 完全な手順はこちら

36
Jason R

これは、スレッド化されたDNSリゾルバーが実装されているDebian changelog に従って、curl7.32.0で修正される必要があります。 Debianパッケージは不安定で、見つけることができます ここ

Ubuntu 12.04-> 13.04の場合、 このPPA を使用できます。

Sudo apt-add-repository ppa:jaywink/curldebian
Sudo apt-get update && Sudo apt-get upgrade

Ubuntu13.10にはcurl7.32が含まれているため、この問題は発生しないはずです。

2
jaywink