C : виртуальные функции в динамической общей библиотеке приводят к segfault

#c #eclipse #dll #segmentation-fault #eclipse-cdt

#c #eclipse #dll #ошибка сегментации #eclipse-cdt

Вопрос:

в приложении, которое я пишу, я динамически загружаю объекты из созданной мной общей библиотеки.

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

Функции могут быть успешно вызваны при создании объектов внутри приложения, вообще не используя динамическую загрузку или разделяемые библиотеки.

Я подозреваю либо концептуальную ошибку, либо какую-то ошибку компиляции / компоновки на моей стороне.

Иерархия классов выглядит примерно так:

BaseClass.h:

class BaseClass : public EvenMoreBaseClass {
public:
virtual bool enroll(const shared_ptr<string> filepath) = 0;
}

Derived.h:

class Derived : public BaseClass {
bool enroll(const shared_ptr<string> filepath);
}

Derived.cpp:

bool Derived::enroll(const shared_ptr<string> filepath) {
cout << "enroll" << endl;
}

(включает и пространство имен, оставленное здесь)

Приложение загружает библиотеку и получает (общий) указатель на объект базового класса (приложение включает BaseClass.h). Могут выполняться все функции, кроме виртуальных.

Разработка выполняется в Eclipse CDT. В настоящее время все находится в одном проекте с разными конфигурациями сборки (.cpp приложения отключен в конфигурации разделяемой библиотеки и наоборот). Компилятором является g 4.4. Все файлы .o иерархии связаны с библиотекой, — установлено значение shared.

Я был бы действительно признателен за любую помощь.

Комментарии:

1. Вы запускали это в отладчике?

2. У меня есть, но я просто получаю segfault при второй попытке доступа к виртуальной функции. Я установил точку останова для имени виртуальной функции, но она никогда не вызывается успешно в библиотеке.

Ответ №1:

Возможно, это очень поздний ответ, но я обнаружил такое же поведение, это происходит, если вы используете dlclose(handle) перед доступом к виртуальному методу (хотя статические методы работали корректно). Поэтому вам не следует закрывать дескриптор библиотеки, пока вы не закончите с объектами из нее.

Ответ №2:

Убедитесь, что dll и исполняемый файл компилируются с точными одинаковыми настройками компилятора. Если они отличаются, компилятор может генерировать код в исполняемом файле, который не соответствует тому, что ожидает dll, и наоборот, что является нарушением ODR.

Обратите внимание, что стандартные типы библиотек, такие как std::string и std::shared_ptr, могут иметь разные макеты, например, в конфигурациях отладки, а также могут меняться между версиями компилятора (даже от одного и того же поставщика).

В общем, вам нужно быть осторожным, используя классы за пределами dll. Обычно рекомендуется иметь дело только со встроенными типами и интерфейсами без состояния.

Ответ №3:

Может ли быть какая-либо разница в размерах типов между проектами, установленными в конфигурациях сборки?

[обновление]

Я сталкивался с подобными проблемами, когда в одном проекте такие типы, как short и long, определены как отличающиеся по размерам от другого проекта, и на классы, содержащие эти типы, ссылаются через один и тот же заголовочный файл. Один проект помещает второе сокращение в байт 2, другой проект считает, что оно находится в байте 4.

У меня также были проблемы с различными значениями заполнения. Один проект дополняет нечетные символы границами в 4 байта, другой считает, что он дополнен границами в 8 байт.

То же самое может быть справедливо и для указателей виртуальных функций, возможно, один проект умещает их в 32 бита, другой ожидает их в 64 бита.

Комментарии:

1. Они включают одни и те же файлы, и я обычно компилирую обе конфигурации. Может ли это быть проблемой, например, одна сборка создает разные файлы .o, чем другая, что приводит к разным типам для библиотеки и приложения? Или вы имеете в виду какие-то другие размеры типов?

2. Спасибо за обновление, я проверю это, когда вернусь к проблеме — поскольку динамическая загрузка в этом проекте скорее «приятная функция», я сначала сосредоточусь на логике приложения.