【问题标题】:error: longjmp causes uninitialized stack frame错误:longjmp 导致未初始化的堆栈帧
【发布时间】:2012-02-29 18:58:35
【问题描述】:

我有一个在 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]

【问题讨论】:

  • This thread 暗示这意味着您尝试 longjmp 到已经退出的堆栈帧。
  • 我解决了这个错误...这似乎是一个 libcurl 错误,通过设置 curl_easy_setopt(curl, CURLOPT_NOSIGNAL, 1) 不再发生错误
  • 将您的答案放入答案中并接受它。我有同样的问题,并用你写的解决方案解决了。也许其他人在谷歌搜索时也会发现这个问题..
  • 似乎在 Debian 不稳定版中已修复:bugs.debian.org/cgi-bin/bugreport.cgi?bug=570436#74 - 版本 7.32.0-1

标签: curl libcurl dbus


【解决方案1】:

我遇到了同样的问题;如上所述,这是一个 curl 错误。我想我会在这里给出一个答案,以汇总有关该问题的所有可用信息。

来自the Red Hat bug report

在没有异步解析器库的情况下构建的 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 已使用标准构建 名称解析器,名称解析时不会发生超时 地点。考虑使用 c-ares 支持构建 libcurl 以启用 异步 DNS 查找,可以很好地为 name 设置超时 在没有信号的情况下解析。

    在大多数情况下显然需要 DNS 超时,因此这不是一个完美的解决方案。如果您有能力在您的系统上重建 libcurl,那么您可以...

  • 有一个名为 c-ares 的异步 DNS 解析器库,curl 能够将其用于名称解析。使用这个库是该问题的首选解决方案(我想大多数 Linux 打包器现在已经解决了这个问题)。要启用 c-ares 支持,首先构建并安装库,然后在构建之前将 --enable-ares 标志传递给 curl 的 configure 脚本。 Full instructions are here.

【讨论】:

  • 是否可以从终端重现此错误?我的进程崩溃提供了类似的堆栈跟踪,但我无法验证问题是否相同。
  • 请注意,使用 c-ares 不会禁用 curl 的基于警报的超时。您仍然应该设置 CURLOPT_NOSIGNAL 选项。
  • 您的解决方案为我解决了这个问题,我有一个 C 线程程序,它在多线程上使用 libcurl curl v.7.64.1 curl 功能 Features: AsynchDNS HTTPS-proxy IPv6 Largefile libz NTLM NTLM_WB SSL TLS-SRP Uni xSockets 操作系统:centos 6.10这个问题与我一起重现仅当我从 cron 作业运行程序时,但如果我从 PHP 文件执行 C 程序,它不会重现
【解决方案2】:

这应该根据 Debian changelog 在 curl 7.32.0 中修复,其中已实现线程 DNS 解析器。 Debian 软件包处于不稳定状态,可以在here 找到。

对于 Ubuntu 12.04 -> 13.04,您可以使用 this PPA

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

Ubuntu 13.10 包含 curl 7.32 所以应该没有这个问题。

【讨论】:

  • 我已经更新了 curl,所以当我打电话给 curl --version 时,我看到它的版本是 7.32.0,但我仍然遇到同样的问题。在 13.04 中,虽然一切正常。
  • 抱歉是哪个版本的Ubuntu出现问题,13.10?
  • 如果我正确阅读了启动板,在我看来,线程 DNS 解析器可能永远不会在启动板 7.32 版本中结束......会做更多检查
【解决方案3】:

尽管讨论指出应该使用 curl 版本 7.32 解决该问题,但即使在带有 gazebo 的 ubuntu 18.04 上使用 curl 版本的 7.52-DEV,我也遇到了崩溃。

使用 gdb 运行凉亭时崩溃的回溯:

*** longjmp causes uninitialized stack frame ***: /home/$USER/gazebo-11.8.1/bin/gzclient terminated

Thread 1 "gzclient" received signal SIGABRT, Aborted.
__GI_raise (sig=sig@entry=6) at ../sysdeps/unix/sysv/linux/raise.c:51
51  ../sysdeps/unix/sysv/linux/raise.c: No such file or directory.
(gdb) backtrace
#0  0x00007ffff5397fb7 in __GI_raise (sig=sig@entry=6) at ../sysdeps/unix/sysv/linux/raise.c:51
#1  0x00007ffff5399921 in __GI_abort () at abort.c:79
#2  0x00007ffff53e2967 in __libc_message (action=action@entry=(do_abort | do_backtrace), fmt=fmt@entry=0x7ffff550f8fb "*** %s ***: %s terminated\n") at ../sysdeps/posix/libc_fatal.c:181
#3  0x00007ffff548db8f in __GI___fortify_fail_abort (need_backtrace=need_backtrace@entry=true, msg=0x7ffff550f8b0 <longjmp_msg> "longjmp causes uninitialized stack frame") at fortify_fail.c:33
#4  0x00007ffff548dbb1 in __GI___fortify_fail (msg=<optimized out>) at fortify_fail.c:44
#5  0x00007ffff548da4d in ____longjmp_chk () at ../sysdeps/unix/sysv/linux/x86_64/____longjmp_chk.S:100
#6  0x00007ffff548d9ab in __longjmp_chk (env=0x7ffff012fb40 <curl_jmpenv>, val=<optimized out>)
    at ../setjmp/longjmp.c:39
#7  0x00007fffefec8745 in  () at /usr/local/lib/libcurl.so
#8  0x00007ffff5398040 in <signal handler called> () at /lib/x86_64-linux-gnu/libc.so.6
#9  0x00007ffff546dcb9 in __GI___poll (fds=0x555559cbe2f0, nfds=4, timeout=7)
    at ../sysdeps/unix/sysv/linux/poll.c:29
#10 0x00007fffed4c56e9 in  () at /usr/lib/x86_64-linux-gnu/libglib-2.0.so.0
#11 0x00007fffed4c57fc in g_main_context_iteration () at /usr/lib/x86_64-linux-gnu/libglib-2.0.so.0
#12 0x00007ffff694a88f in QEventDispatcherGlib::processEvents(QFlags<QEventLoop::ProcessEventsFlag>) ()
    at /usr/lib/x86_64-linux-gnu/libQt5Core.so.5
#13 0x00007ffff68ef90a in QEventLoop::exec(QFlags<QEventLoop::ProcessEventsFlag>) ()
    at /usr/lib/x86_64-linux-gnu/libQt5Core.so.5
#14 0x00007ffff68f89b4 in QCoreApplication::exec() () at /usr/lib/x86_64-linux-gnu/libQt5Core.so.5
#15 0x00007ffff725a856 in gazebo::gui::run(int, char**) (_argc=<optimized out>, _argv=0x7fffffffb4a8)
    at /home/$USER/gazebo-11.8.1/source/gazebo/gui/GuiIface.cc:442
#16 0x00005555555579f4 in main(int, char**) (_argc=1, _argv=0x7fffffffb4a8)
    at /home/$USER/gazebo-11.8.1/source/gazebo/gui/main.cc:32

仔细观察崩溃,libcurl.so 在框架 #7 中被访问,然后崩溃最终发生(框架 #6#0

这种崩溃通常发生在运行 Gazebo 的 15 分钟内,即使程序在空模拟的情况下空闲运行,即模拟中没有加载模型并且没有发生计算,只是 Gazebo 客户端 (gzclient) 正在运行单独与在另一个 shell 上运行的凉亭服务器 (gzserver) 一起运行

在我的 ubuntu 系统中检查 curl 版本(使用 curl --version)时,我得到了

curl 7.52.1-DEV (Linux) libcurl/7.52.1-DEV OpenSSL/1.0.2n zlib/1.2.11
Protocols: dict file ftp ftps gopher http https imap imaps pop3 pop3s rtsp smb smbs smtp smtps telnet tftp 
Features: IPv6 Largefile NTLM SSL libz UnixSockets HTTPS-proxy

上面的 curl 版本明显高于 7.32 但我还是崩溃了。

用 curl 测试

我删除了 ubuntu 18.04 LTS 默认附带的 curl,并从源代码安装了最新的 curl(版本 7.79.1,截至 17.09.2021):

git clone https://github.com/curl/curl.git
cd curl
./buildconf
./configure --with-{dict,file,ftp,ftps,gopher,gophers,http,https,imap,imaps,mqtt,pop3,pop3s,rtsp,smb,smbs,smtp,smtps,telnet,tftp}
make
sudo make install
sudo ldconfig

在此之后,我再次运行我的程序并让它在一夜之间运行,这次是模拟在循环中进行计算,持续了 15 多个小时,并且在早上模拟运行。

所以对我来说,新版本的 curl 似乎解决了凉亭崩溃的问题。

【讨论】:

    猜你喜欢
    • 2021-11-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-10-04
    • 2011-07-02
    • 2014-05-17
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多