Библиотека плагинов Segfault на C ++ с дублирующимися символами - PullRequest
7 голосов
/ 30 ноября 2009

У меня есть кроссплатформенное приложение C ++, которое разбито на несколько общих библиотек и загружает дополнительные функции из общих библиотек плагинов. Предполагается, что библиотеки плагинов являются автономными и функционируют сами по себе, без знания или зависимости от вызывающего приложения.

Один из плагинов содержит скопированный код из основного приложения, поэтому содержит имена символов, которые совпадают с именами в движке. (Да, я знаю, что обычно это нет-нет, но в то время, когда плагин был написан, движок был монолитным двоичным файлом и не мог совместно использовать библиотеки.) В Windows все работает нормально. В Linux мы получали segfaults. Посмотрев на трассировку стека ошибки, она возникла в плагине при вызове функций с повторяющимся именем класса. Похоже, это было результатом того, что движок и плагин имели несколько разные версии общего кода (некоторые функциональные возможности класса были закомментированы в плагине). Это было так, как будто плагин связывал свои символы времени выполнения с движком, а не со своим собственным. Мы «исправили» проблему, изменив параметры dlopen на dlopen(pFilepath, RTLD_LAZY | RTLD_LOCAL).

Но когда мы переписали движок для разделения на разделяемые библиотеки (для возможного повторного использования в плагинах), мы снова получаем ошибку segfault. И, глядя на трассировку стека, он идет от двигателя -> плагин -> двигатель.

Есть ли способ указать для компоновщика времени выполнения, чтобы он не отображал символы плагина на движок (особенно, если они определены в плагине)?

Спасибо! Matt


Отредактировано 2009-12-3

Сначала я попытался обернуть код плагина в его собственное пространство имен. Это не сработало, потому что оно статически связано с библиотекой, которая также связана с движком. Версии статической библиотеки разные, так что segfault!

Затем я изменил сборку движка и его библиотек, чтобы они были статически связаны. И когда я запускаю его, у меня больше нет проблемы. Таким образом, похоже, что это было результатом того, что символы общей библиотеки были экспортированы, а затем динамически перемещены в плагин, когда он был открыт. Но когда весь код движка находится в одном исполняемом файле, он не экспортирует свои символы (поэтому он не пытается переместить символы плагина в движок).

У меня все еще есть проблема, поскольку есть распараллеленная версия программы (использующая Open-MPI), и она все еще получает ошибку сегмента. Похоже, он все еще экспортирует символы движка и перемещает плагин. Это может быть связано с тем, как Open-MPI выполняет приложение.

Существуют ли какие-либо флаги компоновщика, которые можно было бы использовать в разделяемой библиотеке плагина, который бы указывал ей не динамически перемещать символы во время выполнения? Или скрыть символы, чтобы они не перемещались? Я пробовал -s («Опустить всю символьную информацию»), но это, очевидно, не изменило динамические символы (проверено с помощью nm -D <plugin>).

Ответы [ 3 ]

4 голосов
/ 04 декабря 2009

Мне кажется, я нашел решение, флаг компоновщика -Bsymbolic. По сути, этот флаг добавляет флаг в разделяемую библиотеку, чтобы указать компоновщику среды выполнения сначала попытаться разрешить имена символов внутри себя. Движок мог работать с плагином очень хорошо во всех случаях (монолитный exe, exe с общими библиотеками, плагин с / без обертывания пространства имен), когда плагин был связан с этим флагом.

Кажется, есть несколько хулителей с предупреждениями о -Bsymbolic:
http://www.technovelty.org/code/c/bsymbolic.html
http://software.intel.com/en-us/articles/performance-tools-for-software-developers-bsymbolic-can-cause-dangerous-side-effects/

Но, учитывая их предупреждения и намерения плагина, я думаю, что это правильный выбор для меня. По крайней мере, пока.

1 голос
/ 30 ноября 2009

Я согласен с Гленом - вы действительно не решите это, если не измените имена классов, возможно, через пространства имен. Даже 36 файлов, вероятно, потребуется меньше времени для изменения, чем попытка надежного исправления без изменения имен символов.

Начните с определения всех классов, имена которых необходимо настроить. Ваш компоновщик, вероятно, уже перечисляет их для вас. Затем я бы хотя бы временно изменил имена обоих наборов классов (от Foo до Engine :: Foo и Plugin :: Foo). Таким образом, вы можете заставить компилятор найти все ссылки на проблемные классы. Перейдите к источнику плагина, пока он не скомпилируется со ссылками на правильные новые имена классов плагина. Как только это будет сделано, измените классы Engine :: на их старые имена (если только вы не хотите постоянно изменять исходный код движка, что, по-вашему, не так). Теперь плагин должен компилировать и ссылаться на правильные классы с уникальными именами.

0 голосов
/ 30 ноября 2009

Я бы просто обернул ВСЕ код плагина пространством имен PluginX. Это, безусловно, избавит вас от этих ошибок. В любом случае, это очень хорошая, важная практика.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...