Вопрос по c++ – Исключения через бинарную границу

21

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

У меня следующая ситуация:

   A
  / \
 /   \
B <-- C
A - это разделяемая библиотека, которая содержит классEExceptionB и C ссылка против AC также является общей библиотекойB динамически загружает C во время выполнения

В какой-то момент C бросает экземплярEException:

void doSometing() {
    throw EException("test-message");
}

вB Я хотел бы поймать это исключение:

try {
    doSomething();
} catch (const EException& ex) {
    // Not reached
} catch (...) {
    // Not reached
}

Но, как уже упоминалось в коде, ни одно из предложений catch не вызывается. Вместо этого поток, в котором выполняется этот код, прерывается.

Я пробовал следующие вещи:

Атрибут видимостиEException установлен на "по умолчанию" при компиляции ATheEException заголовочный файл содержит только объявления Я использую опцию линкера-fvisibility=hidden в А, В и С Я использую опцию линкера-E в С

С помощьюnm Я получаю заA:

0000000000066260 T EException::EException(QString const&)
0000000000066306 T EException::EException(EException const&)
00000000000661d0 T EException::EException() 
0000000000066260 T EException::EException(QString const&) 
0000000000066306 T EException::EException(EException const&) 
00000000000661d0 T EException::EException() 
00000000000664de T EException::~EException()
000000000006641e T EException::~EException() 
000000000006641e T EException::~EException() 
00000000000663b6 T EException::operator=(EException const&)
<...>
000000000028de40 V typeinfo for EException
000000000028dd80 V typeinfo for EException*
000000000007342b V typeinfo name for EException
0000000000072ab7 V typeinfo name for EException*
000000000028de00 V vtable for EException

дляB:

U EException::EException(QString const&)
U EException::~EException()
<...>
0000000000726f60 V typeinfo for EException

и дляC:

U EException::EException(QString const&)
U EException::~EException()
<...>
U typeinfo for EException

Может быть проблема в том, чтоB использует свою собственную информацию типаEException, в то время какC использует предоставленныйA? Как бы это исправить?

Моя среда:

gcc 4.6.3 на x86_64-linux-gnuusing Qt

Спасибо за помощь

Чтоcatch(...) не означает, что ваша ошибка не связана с вашим классом исключений (или с ошибкой в ctor). Вы пытались отладить его и посмотреть, что происходит на этой линии броска? edA-qa mort-ora-y
На строке броска конструктор копированияEException вызывается. В конструкторе копирования нет ошибки, и после его завершения поток прерывается. Sämy
Также смdynamic_cast, throw, typeid не работают с общими библиотеками из GCC FAQ. Он говорит вам, чтобы @ Избежа the-Bsymbolic компоновщик, и использовать-Eпция @ linker. Я также думаю,B должен использовать--exclude-libs ALL. jww

Ваш Ответ

5   ответов
3

4.5 с символами RTTI, используемыми через границы общей библиотеки, но не с gcc 4.6. Тем не менее, вы все равно можете найти следующую информацию полезной.

Как уже упоминалось, vtable (содержащий запись в объекте typeinfo) дляEExceptionажется, что @ дублируется в некоторых единицах перевода, что определенно было проблемой с gcc <4.5 (ну, это проблема libsupc ++, насколько я знаю, не объединение объектов type_info). Закрепление vtable ofEException путем определения виртуального деструктора вне строки (это должно быть первое объявление виртуальной функции в заголовке) вA помог мне.

Размещение полного файла заголовка дляEException также может быть полезным.

1

-Fvisibility = скрытый

option в настройках компоновщика. Если он установлен, измените его на

-Fvisibility = по умолчанию

1

Определите ваш объект исключения как extern и не предоставляйте никакой реализации, кроме как в вашем основном двоичном файле.

Это заставит компоновщик (динамический компоновщик BTW) использовать единственную возможную реализацию.

Нет typeinfo генерируется только для внешнего определения.

0

V typeinfo for EException тогда как C, похоже, использует Unresolved (U означает, что тип не определен в текущей единице перевода и должен быть разрешен загрузчиком и динамическим компоновщиком).

Убедитесь, что B по-прежнему является разделяемой библиотекой, и она не связана статически с A, но динамически препятствует тому, чтобы C обнаружил материалы Findind A, потому что, как я не вижу, B не будет связывать тот же тип, что и A. Позаботьтесь о своем заголовке ^^ .

Я понимаю твою первую часть. НоB - это мое основное приложение, но нет общей библиотеки. И то и другоеB а такжеC ссылкаA во время компиляции. Насколько я понимаю, я должен предотвратиB от использования собственной информации типаEException поскольку обаB а такжеC автоматически загружаютсяA во время выполнения и должен использоватьA s typeinfo тогда. Sämy
0

A, B а такжеC с-rdynamic (на этапе связывания)

Справочная страница GCC расскажет о -rdynamic:

Передайте флаг -export-dynamic в компоновщик ELF для целей, которые его поддерживают. Это указывает компоновщику добавлять все символы, а не только используемые, в таблицу динамических символов. Эта опция необходима для некоторых случаев использования Dlopen "или чтобы разрешить получение следов из программы.

Похожие вопросы