Исключения через двоичную границу
Я знаю, этот вопрос задавался довольно часто, однако я не могу найти решение для своей проблемы.
У меня следующая ситуация:
A
/ \
/ \
B <-- C
- A - это общая библиотека, которая содержит класс
EException
- Ссылка B и C на A
- C также является общей библиотекой
- B динамически загружает C во время выполнения
В какой-то момент C выдает экземпляр EException
:
void doSometing() {
throw EException("test-message");
}
in B
Я хотел бы поймать это исключение:
try {
doSomething();
} catch (const EException& ex) {
// Not reached
} catch (...) {
// Not reached
}
но, как указано в коде, ни один из предложений catch не вызван. Вместо этого поток, этот код выполняется, прерывается.
Я пробовал следующие вещи:
- При компиляции A атрибут видимости
EException
устанавливается как "по умолчанию",
Заголовочный файл
EException
содержит только декларации
Я использую опцию компоновщика
-fvisibility=hidden
в A, B и C
Я использую опцию компоновщика
-E
в C
Используя 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
использует свой собственный типinfo EException
, а C
использует тот, который предоставляется A
? Как я могу это исправить?
Моя среда:
- gcc 4.6.3 на x86_64-linux-gnu
- с помощью Qt
Благодарим за помощь!
Ответы
Ответ 1
У меня были аналогичные проблемы с gcc < 4.5 с символами RTTI, используемыми на границах разделяемых библиотек, но не с gcc 4.6. Однако вы все равно можете найти следующую информацию.
Как уже упоминалось, vtable (содержащая запись для объекта typeinfo) для EException
, по-видимому, дублируется в некоторых единицах перевода, что определенно является проблемой с gcc < 4.5 (хорошо, это проблема libsupС++, насколько я знаю, не слияние объектов type_info). Закрепление vtable EException
путем определения виртуального деструктора вне строки (оно должно быть первым объявлением виртуальной функции в заголовке) в A
помогло.
Также может быть полезно опубликовать полный файл заголовка для EException
.
Ответ 2
Проверить
-fvisibility = скрытый
в настройках компоновщика.
Если он установлен, измените его на
-fvisibility = по умолчанию
Ответ 3
IMHO, это как ничего общего с флагов компилятора.
Объявите свой объект исключения как extern и не предоставляйте никакой реализации нигде, кроме основного файла.
Это заставит компоновщик (динамический компоновщик BTW) использовать единственную возможную реализацию.
Нет типаinfo генерируется только для определения extern.
Ответ 4
B использует его собственное определение класса EException V typeinfo for EException
, тогда как C, похоже, использует неразрешенный (U означает, что тип undefined в текущем блоке перевода и должен быть разрешен загрузчиком и динамическим компоновщиком).
Убедитесь, что B все еще является общей библиотекой, и она не связана статически с A, но динамически, не позволяя C находить. Продукты, вызываемые, поскольку я не могу видеть, что B не будет связывать тот же тип, что и A. Позаботьтесь о своем заголовке ^^.
Ответ 5
Вы можете попытаться скомпилировать A
, B
и C
с помощью -rdynamic
(на этапе соединения)
На странице GCC рассказывается о -rdynamic:
Передайте флаг -export-dynamic в листинг-лист ELF, на целевые объекты, которые его поддерживают. Это дает ссылку компоновщику добавлять все символы, а не только используемые, в таблицу динамических символов. Этот параметр необходим для некоторых видов использования "dlopen" или для получения обратных трасс из программы.