Segfault во время __cxa_allocate_exception в обернутой библиотеке SWIG
При разработке SWIG-библиотеки С++ для Ruby мы столкнулись с необъяснимым сбоем при обработке исключений внутри кода С++.
Я не уверен в конкретных обстоятельствах, чтобы воссоздать проблему, но это произошло во время вызова std::uncaught_exception
, а затем после изменения какого-либо кода, переместился на __cxa_allocate_exception
во время построения исключения. Ни GDB, ни valgrind не дали никакого понимания причины аварии.
Я нашел несколько ссылок на похожие проблемы, в том числе:
Приоритетная тема, кажется, представляет собой сочетание обстоятельств:
- Приложение C связано с более чем одной библиотекой С++.
- Во время компиляции была использована более одной версии libstdС++.
- Обычно вторая версия С++ используется из бинарной реализации libGL
- Проблема не возникает при связывании вашей библиотеки с приложением С++, только с приложением C
"Решение" - это явно связать вашу библиотеку с libstdС++ и, возможно, также с libGL, заставляя порядок связывания.
После нескольких комбинаций с моим кодом единственным решением, которое я нашел, что работает, является параметр LD_PRELOAD="libGL.so libstdc++.so.6" ruby scriptname
. То есть ни один из решений компоновки времени не имел никакого значения.
Мое понимание проблемы заключается в том, что среда выполнения С++ не была правильно инициализирована. Заставляя порядок связывания вы запускаете процесс инициализации, и он работает. Проблема возникает только с приложениями C, вызывающими библиотеки С++, потому что приложение C не связано непосредственно с libstdС++ и не инициализирует среду выполнения С++. Поскольку использование SWIG (или boost:: python) является распространенным способом вызова библиотеки С++ из приложения C, вот почему SWIG часто возникает при исследовании проблемы.
Есть ли кто-нибудь, кто мог бы лучше понять эту проблему? Существует ли реальное решение или существуют только обходные пути?
Спасибо.
Ответы
Ответ 1
Следуя предложению Майкла Доргана, я копирую свой комментарий в ответ:
Нашел настоящую причину проблемы. Надеюсь, это поможет кому-то еще столкнуться с этой ошибкой. Вероятно, у вас есть какие-то статические данные, которые не были правильно инициализированы. Мы это сделали, и решение было в boost-log для нашей базы кода. https://sourceforge.net/projects/boost-log/forums/forum/710022/topic/3706109. Реальной проблемой является библиотека с задержкой загрузки (плюс статика), а не потенциально несколько версий С++ из разных библиотек. Для получения дополнительной информации: http://parashift.com/c++-faq-lite/ctors.html#faq-10.13
Поскольку мы сталкиваемся с этой проблемой и ее решением, я узнал, что важно понять, как статика делится или не делится между вашими статически и динамически связанными библиотеками. В Windows это требует явного экспорта символов для общей статики (включая такие вещи, как одиночные списки, предназначенные для доступа через разные библиотеки). Поведение тонко отличается между каждой из основных платформ.
Ответ 2
Недавно я столкнулся с этой проблемой. Мой процесс создает общий объектный модуль, который используется как расширение на языке С++ python. Недавнее обновление ОС с RHEL 6.4 до 6.5 выявило проблему.
Следуя советам здесь, я просто добавил -lstdС++ к моим переключателям ссылок и решил проблему.
Ответ 3
Имея такую же проблему, используя SWIG для Python с библиотекой cpp (Clipper), я обнаружил, что использование LD_PRELOAD, как вы предлагали, работает и для меня.
В качестве другого обходного решения, которое не требует LD_PRELOAD, я обнаружил, что я также могу связать libstdС++ с библиотечным файлом .so моего модуля, например.
ld -shared /usr/lib/i386-linux-gnu/libstdc++.so.6 module.o module_wrap.o -o _module.so
Затем я могу импортировать его в python без дополнительных параметров.
Ответ 4
Я понимаю, что @lefticus принял ответ, относящийся к тому, что я думаю, составляет undefined статический порядок инициализации; однако у меня была очень похожая проблема, на этот раз с boost::python
.
Я пробовал, что прошу, чтобы найти какие-то статические проблемы с инициализацией и не смог - до такой степени, что я реорганизовал основной кусок нашей кодовой базы; и когда это не сработало, в конечном итоге удалены исключения.
Однако еще немного подкрались, и мы снова начали получать эти segfaults.
После еще нескольких исследований я наткнулся на эту ссылку, в которой говорится о пользовательских распределителях.
Мы действительно используем tcmalloc
самих себя; и после того, как я удалил его из нашей библиотеки, которая экспортируется в boost::python
, у нас больше не было проблем!
Так просто FYI для всех, кто наткнулся на этот поток - если ответ @lefticus не работает, проверьте, используете ли вы другой распределитель для того, что использует python
.