Конфликт имен при динамической загрузке
От: Eugene Kilachkoff Россия  
Дата: 22.11.04 10:06
Оценка:
Нарвалсь вот на такое странное поведение. Дано:
1. Наша система. Язык реализации — C++. В системе реализован класс с именем, скажем, CFoo. Ну, то есть, в основном бинарнике находятся реализации CFoo::CFoo(), CFoo::~CFoo() и некоторых методов.
2. Сторонняя библиотека (.so). Реализована также на C++, однако наружу торчит только C-style API, типа LibObject_Create(), LibObject_Work(), LibObject_Delete(). В частности, эти три функции являются оберткой для создания и удаления класса с именем ... правильно, CFoo

Мы загружаем библиотеку с помощью dlopen, резолвим LibObject_Create() и иже с ним, и начинаем с ней работать. Ну, все совершенно просто
LibObject *o = LibObject_Create();
int result = LibObject_Work(o,some_data);
cout << result << endl;
LibObject_Delete(o); // ( !!! )


В момент вызова LibObject_Delete прибегает пушной зверек А именно, вызывается наш деструктор для CFoo, только в качестве аргумента ему передается указатель на их CFoo, контролируемый оберткой с помощью LibObject *o. Естественно, у него съезжает крыша и наступает локальное помешательство, заканчивающееся SIGSEGV.
Дизассембер вполне четко показывает, что это не просто вызов куда попало (и попало почему-то к нам), а просто оно так отрезолвилось. В исходном сошнике это место указано в таблице релокаций, ну и линкер туда благополучно пихает указатель на нашу функцию. Переименование нашего класса CFoo в CBar лечит проблему, но это же не наш метод !!
Посему вопрос: какого, собсно, оно так делает ?
В тестовом примере воспроизвести не удалось — резолвится как нужно.

Система — linux с glibc 2.3 (whitebox respin1)
Re: Конфликт имен при динамической загрузке
От: aka50 Россия  
Дата: 22.11.04 11:02
Оценка:
Здравствуйте, Eugene Kilachkoff, Вы писали:

EK>Нарвалсь вот на такое странное поведение. Дано:

EK>1. Наша система. Язык реализации — C++. В системе реализован класс с именем, скажем, CFoo. Ну, то есть, в основном бинарнике находятся реализации CFoo::CFoo(), CFoo::~CFoo() и некоторых методов.
EK>2. Сторонняя библиотека (.so). Реализована также на C++, однако наружу торчит только C-style API, типа LibObject_Create(), LibObject_Work(), LibObject_Delete(). В частности, эти три функции являются оберткой для создания и удаления класса с именем ... правильно, CFoo

<skip>

EK>Дизассембер вполне четко показывает, что это не просто вызов куда попало (и попало почему-то к нам), а просто оно так отрезолвилось. В исходном сошнике это место указано в таблице релокаций, ну и линкер туда благополучно пихает указатель на нашу функцию. Переименование нашего класса CFoo в CBar лечит проблему, но это же не наш метод !!

EK>Посему вопрос: какого, собсно, оно так делает ?
EK>В тестовом примере воспроизвести не удалось — резолвится как нужно.

EK>Система — linux с glibc 2.3 (whitebox respin1)


Как говорится "по телефону" сложно... , но предположений несколько:
1. Данный символ почему-то может быть помечен WEAK
2. Резолвинг производится как RTLD_GLOBAL, т.е. линкер ищет первое вхождение символа
в DAG загруженных модулей, и естетсвенно, ваш класс находится выше по DAG-у и его он и пихает.

Варианты решения видится один (помимо переименования): использовать namespace для вашего класса и прям в
хидере прописать using. Это изменит имя вашего скласса в .o, но в программе ничего менять не придется...
Re[2]: Конфликт имен при динамической загрузке
От: aka50 Россия  
Дата: 22.11.04 11:04
Оценка:
Здравствуйте, aka50, Вы писали:

A>2. Резолвинг производится как RTLD_GLOBAL, т.е. линкер ищет первое вхождение символа

A>в DAG загруженных модулей, и естетсвенно, ваш класс находится выше по DAG-у и его он и пихает.

Тут GLOBAL не причем.... должно звучать так:
2. Линкер ищет первое вхождение символа в DAG загруженных модулей, и естетсвенно, ваш класс находится
выше по DAG-у и его он и пихает.
Re[3]: Конфликт имен при динамической загрузке
От: Eugene Kilachkoff Россия  
Дата: 22.11.04 11:36
Оценка:
Здравствуйте, aka50, Вы писали:

A>Здравствуйте, aka50, Вы писали:


A>>2. Резолвинг производится как RTLD_GLOBAL, т.е. линкер ищет первое вхождение символа

A>>в DAG загруженных модулей, и естетсвенно, ваш класс находится выше по DAG-у и его он и пихает.

A>Тут GLOBAL не причем.... должно звучать так:

A>2. Линкер ищет первое вхождение символа в DAG загруженных модулей, и естетсвенно, ваш класс находится
A>выше по DAG-у и его он и пихает.
RTLD_LOCAL. А почему он может быт выше и почему в тестовом примере этого не происходит ? Сорри за телепатию, переформулирую: что влияет на положение символа в DAG ?

ps. на первый вопрос ответ "нет". Обычный global text — "T".
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.