2009-11-30 2 views
7

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

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

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

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

Спасибо! Matt


Edited 2009-12-3

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

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

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

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

+0

Являются ли эти символы глобальными или именами функций? Можете ли вы внести незначительные изменения в код? –

+0

Это классы и их функции-члены. Есть 36 файлов, используемых из кодовой базы двигателя, поэтому я не хочу изменять каждое имя или файл класса. Хотя конечной целью является переписать плагин из-за ограничений по времени и проверки кода, который я не хочу, если мне это не нужно. – CuppM

+0

@CuppM, так, например, у вас есть класс «Foo» с членом «bar», определенным в 2-х местах? И «Foo» находится в том же пространстве имен в обоих случаях? Если это так, это никогда не будет работать правильно для вас. Переместите одно из «Foo» в собственное пространство имен, и жизнь будет проще. – Glen

ответ

4

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

Там, кажется, несколько недоброжелателей с предупреждениями о -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

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

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

+0

Хотя вы, вероятно, прав насчет этого. Это не удовлетворительный ответ, так что я собираюсь оставить вопрос без ответа на всякий случай на всякий случай. Я изменю код плагина, чтобы добавить пространство имен к битам-нарушителям. Пока я не могу переписать его с использованием общих библиотек движка, так как я изменил весь код в движке, не имеет значения, модифицирую ли я копию. – CuppM

0

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

Смежные вопросы