Ошибка: 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]

3 ответа

Я столкнулся с той же проблемой; как отмечено выше, это ошибка скручивания. Я думал, что выложу здесь ответ, чтобы собрать всю доступную информацию о проблеме.

Из отчета об ошибке 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_easy_setopt(curl, CURLOPT_NOSIGNAL, 1) на всех ручках скручивания, которые вы используете. Документация для CURLOPT_NOSIGNAL заметки:

    Пройти по. Если это значение равно 1, libcurl не будет использовать какие-либо функции, которые устанавливают обработчики сигналов, или любые функции, которые вызывают отправку сигналов процессу. Эта опция в основном здесь, чтобы позволить многопоточным приложениям Unix по-прежнему устанавливать / использовать все параметры тайм-аута и т. Д., Не рискуя получить сигналы. (Добавлено в 7.10)

    Если эта опция установлена, и libcurl был собран со стандартным распознавателем имен, тайм-ауты не будут происходить, пока происходит разрешение имени. Рассмотрите возможность создания libcurl с поддержкой c-ares, чтобы включить асинхронный поиск DNS, который обеспечивает хорошие тайм-ауты для разрешения имен без сигналов.

    Тайм-ауты DNS, очевидно, желательно иметь в большинстве случаев, так что это не идеальное решение. Если у вас есть возможность пересобрать libcurl в вашей системе, то вы можете...

  • Существует библиотека асинхронного распознавателя DNS, называемая c-ares, которую curl может использовать для разрешения имен. Использование этой библиотеки является предпочтительным решением проблемы (и я полагаю, что большинство упаковщиков Linux уже поняли это). Чтобы включить поддержку c-ares, сначала соберите и установите библиотеку, а затем передайте --enable-ares флаг керла configure Сценарий, прежде чем строить. Полные инструкции здесь.

Это должно быть исправлено в curl 7.32.0 в соответствии с журналом изменений Debian, в котором реализован многопоточный преобразователь DNS. Пакет Debian находится в нестабильном состоянии и может быть найден здесь.

Для Ubuntu 12.04 -> 13.04 вы можете использовать этот PPA.

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

Ubuntu 13.10 включает в себя curl 7.32, поэтому не должно быть этой проблемы.

Несмотря на то, что в обсуждении указывается, что проблема должна быть решена с помощью curl версии 7.32, я получал сбой даже с версией curl 7.52-DEV на ubuntu 18.04 с gazebo.

След аварии при запущенной беседке с 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)

Этот сбой обычно происходит в течение 15 минут после запуска беседки, даже когда программа остается работающей в режиме ожидания с пустой симуляцией, т. Е. В симуляции не загружена модель и не производятся вычисления, только клиент беседки ( gzclient) работает сам по себе с сервером беседки ( gzserver) работает на другой оболочке

При проверке версии curl (используя curl --version) в моей системе ubuntu я получаю

      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 (версия 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.

Другие вопросы по тегам