Подтвердить что ты не робот

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 часто возникает при исследовании проблемы.

Есть ли кто-нибудь, кто мог бы лучше понять эту проблему? Существует ли реальное решение или существуют только обходные пути?

Спасибо.

4b9b3361

Ответ 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.