1) Имеется большая страшная динамическая библиотека, размером > 100МБ, полученная из успешно работающей большой страшной программы-демона (грубо говоря, просто добавил при компиляции параметр "-shared", не суть важно).
3) Если выполняется malloc(//1), то malloc'и(1,2,3) выволняются нормально, но внутри so обламывается вызов new (причём, по-видимому, обламываются не все, а лишь некоторые но точно определить на получается ввиду нереальных объёмов библиотеки — предположительно в конструкторе возникает исключение, но почему-то оно не ловится под gdb и не приводит к coredump'у, вернее, приводит, но лишь косвенно, и значительно позже — при обращении к непроинициализированным данным).
Если же malloc(//1) отсутствует — то всё работает хорошо.
Из того, что может помочь телепатам: всё это безобразие собирается с -lthr -lperl. Perl также собирался с libthr, версии библиотек совпадают. Perl не использовал свой аллокатор (-Ui_malloc -Dusemymalloc=n). И so и тестовая программа собирались с -Wl,-E — без этого не находится boot_DynaLoader.
4) Зачем это всё нужно — предполагается, что эта so будет вызываться из perl'а через xs. Собственно, эффект полностью воспроизводится — perl подгружает so, дёргает процедуру, вызывающую libinit — и падает в корку при обращении к непроинициализированным данным.
Help!
Курица — это инструмент, с помощью которого одно яйцо производит другие.
Была похожая штука. Проект на MVC. Компилурую, запускаю — ошибка. По дебагеру добираюсь до места ошибки — падает на new.
Через несколько дней поисков и эксперементов выяснил, что если добавить в начале программы выделение памяти malloc, то ошибка пропадала.
Причем пропадала в отладочном режиме, а в Release полюбому вылезала.
Неделе через две обнаружилось, что у объекта, который создавал по new в конструкторе была ошибка, я там выделял память под массив меньше, чем надо, а потом в него писал.
В результате затирались важные данные. А если этот malloc вызывал, то память по-другому немного выделялась и затирались второстепенные данные, которые к ошибке не приводили.
Здравствуйте, frogkiller, Вы писали:
F>Need help!
F>1) Имеется большая страшная динамическая библиотека, размером > 100МБ, полученная из успешно работающей большой страшной программы-демона (грубо говоря, просто добавил при компиляции параметр "-shared", не суть важно).
Не содержит ли эта большая страшная динамическая библиотека внутри свой собственный malloc?
Здравствуйте, dilettante, Вы писали:
F>>1) Имеется большая страшная динамическая библиотека, размером > 100МБ, полученная из успешно работающей большой страшной программы-демона (грубо говоря, просто добавил при компиляции параметр "-shared", не суть важно).
D>Не содержит ли эта большая страшная динамическая библиотека внутри свой собственный malloc?
Не содержит. Perl также сконфигурен не использовать свой malloc.
В общем с помощью бубна я это дело вроде как отловил, но результат меня, мягко говоря, озадачил. Сейчас отпишусь ниже.
Курица — это инструмент, с помощью которого одно яйцо производит другие.
Вроде как нашёл причину, но результат меня озадачил. Внутри библиотеки был такой код:
someGlobaldata = new MyMegaClass();
Я думал, что это new возвращает битые данные, но всё оказалось хитрее:
extern__thread MyMegaClass * someGlobaldata; //он оказывается свой в каждом потоке, объявление скрыто в глубе исходников
...
void libinit()
{
MyMegaClass * tmpData = new MyMegaClass(); // внутри очень много действий, включая создание множества разнообразных потоков
someGlobaldata = tmpData;
fprintf(stderr, "%p, %p", tmpData, someGlobaldata); // печатает 0x69a110, 0x0 -- глазам не верю, один поток, последовательные команды, присваивание не работает!!!!
}
Вероятно, дело в том, что someGlobaldata является потоковыми данными:
nm ./my_big_library.so | grep someGlobaldata
0000000000000010 B someGlobaldata
Но что-то мне не очень верится, что я полностью победил проблему, ибо не понимаю её, такое не очень приятное ощущение, что она проявится снова в самый неприятный момент
PS. Подумал было, что может быть причина в переупорядочении последовательности команд компилятором, о которой не так давно писал remark, поставил вместо "someGlobaldata = 0;" мьютекс — не помогло
Курица — это инструмент, с помощью которого одно яйцо производит другие.
F>Но что-то мне не очень верится, что я полностью победил проблему, ибо не понимаю её, такое не очень приятное ощущение, что она проявится снова в самый неприятный момент
F>PS. Подумал было, что может быть причина в переупорядочении последовательности команд компилятором, о которой не так давно писал remark, поставил вместо "someGlobaldata = 0;" мьютекс — не помогло
Здравствуйте, eugene hermann, Вы писали:
EH>Может дело в этом: EH>
EH>In C++, if an initializer is present for a thread-local variable, it must be a constant-expression, as defined in 5.19.2 of the ANSI/ISO C++ standard.
Увы, нет. Инициализатор присутствует (в месте объявления переменной в глубине библиотеки) и он равен нулю. Здесь же обычное присваивание.
Выяснилось, что лечит не только запись в эту переменную, а вообще любая запись в tls — первая обламывается, а остальные проходят нормально.
Пока я склоняюсь к выводу, что меня обманывает __tls_get_addr. Вообще обращения к переменной происходят всегда так:
leaq someGlobaldata@TLSGD(%rip), %rdi
rex64
call __tls_get_addr@PLT
movq %rbx, (%rax) # очевидно, адрес переменной кладётся в %rax
Вот ещё кстати, кто-нибудь может мне объяснить что имеется ввиду здесь:
On amd64 the assembler does not support thread-local access relocations in 64-bit mode (binutils 2.13.2).
?
У меня как раз FreeBSD7 на amd64.
Курица — это инструмент, с помощью которого одно яйцо производит другие.