нехороший malloc, нужны телепаты
От: frogkiller Россия  
Дата: 13.10.08 11:55
Оценка:
Need help!

1) Имеется большая страшная динамическая библиотека, размером > 100МБ, полученная из успешно работающей большой страшной программы-демона (грубо говоря, просто добавил при компиляции параметр "-shared", не суть важно).

2) Создаю программу-заглушку для тестирования:
#include <stdlib.h>
#include <stdio.h>
#include <dlfcn.h>
#include <unistd.h>

int main(int argc, char **argv) {
    void * aaa = (argc > 2) ?  malloc(1000) : 0;                              //1
    void * handle = dlopen ("./my_big_library.so", RTLD_LAZY);
    if (!handle) {
        return 1;
    }

    void * ccc = (argc > 1) ?  malloc(1000) : 0;                              //2

    void (*libinit)(void) = (void (*)(void))dlsym(handle, "my_lib_init");

    libinit();   

    void * bbb = malloc(1000);                                                //3

    while (true) sleep(100);

    dlclose(handle);
    //free(aaa);
    //free(bbb);
    //free(ccc);
}


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!
Курица — это инструмент, с помощью которого одно яйцо производит другие.
Re: нехороший malloc, нужны телепаты
От: Shasoft Россия http://shasoft.com
Дата: 13.10.08 12:16
Оценка:
А в самой библиотеки точно всё пучком?

Была похожая штука. Проект на MVC. Компилурую, запускаю — ошибка. По дебагеру добираюсь до места ошибки — падает на new.
Через несколько дней поисков и эксперементов выяснил, что если добавить в начале программы выделение памяти malloc, то ошибка пропадала.
Причем пропадала в отладочном режиме, а в Release полюбому вылезала.

Неделе через две обнаружилось, что у объекта, который создавал по new в конструкторе была ошибка, я там выделял память под массив меньше, чем надо, а потом в него писал.
В результате затирались важные данные. А если этот malloc вызывал, то память по-другому немного выделялась и затирались второстепенные данные, которые к ошибке не приводили.
Re[2]: нехороший malloc, нужны телепаты
От: frogkiller Россия  
Дата: 13.10.08 12:54
Оценка:
Здравствуйте, Shasoft, Вы писали:

S>А в самой библиотеки точно всё пучком?


Точно всё пучком. Тот же код в виде демона работает вполне корректно.

S>Причем пропадала в отладочном режиме, а в Release полюбому вылезала.


Всё, разумеется, в дебаге.
Курица — это инструмент, с помощью которого одно яйцо производит другие.
Re: нехороший malloc, нужны телепаты
От: dilettante  
Дата: 13.10.08 15:38
Оценка:
Здравствуйте, frogkiller, Вы писали:

F>Need help!


F>1) Имеется большая страшная динамическая библиотека, размером > 100МБ, полученная из успешно работающей большой страшной программы-демона (грубо говоря, просто добавил при компиляции параметр "-shared", не суть важно).


Не содержит ли эта большая страшная динамическая библиотека внутри свой собственный malloc?
Re[2]: нехороший malloc, нужны телепаты
От: frogkiller Россия  
Дата: 13.10.08 15:56
Оценка:
Здравствуйте, dilettante, Вы писали:

F>>1) Имеется большая страшная динамическая библиотека, размером > 100МБ, полученная из успешно работающей большой страшной программы-демона (грубо говоря, просто добавил при компиляции параметр "-shared", не суть важно).


D>Не содержит ли эта большая страшная динамическая библиотека внутри свой собственный malloc?


Не содержит. Perl также сконфигурен не использовать свой malloc.

В общем с помощью бубна я это дело вроде как отловил, но результат меня, мягко говоря, озадачил. Сейчас отпишусь ниже.
Курица — это инструмент, с помощью которого одно яйцо производит другие.
Re: нехороший malloc, нужны телепаты
От: frogkiller Россия  
Дата: 13.10.08 16:18
Оценка:
Здравствуйте, frogkiller, Вы писали:

F>Need help!


Вроде как нашёл причину, но результат меня озадачил. Внутри библиотеки был такой код:
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


Вылечилось вот таким странным образом:
void libinit()
{
    someGlobaldata = 0;
    someGlobaldata = new MyMegaClass();

    fprintf(stderr, "%p", someGlobaldata); // печатает 0x69a110
}

Но что-то мне не очень верится, что я полностью победил проблему, ибо не понимаю её, такое не очень приятное ощущение, что она проявится снова в самый неприятный момент

PS. Подумал было, что может быть причина в переупорядочении последовательности команд компилятором, о которой не так давно писал remark, поставил вместо "someGlobaldata = 0;" мьютекс — не помогло
Курица — это инструмент, с помощью которого одно яйцо производит другие.
Re[2]: нехороший malloc, нужны телепаты
От: eugene hermann Беларусь  
Дата: 14.10.08 20:56
Оценка:
Здравствуйте, frogkiller, Вы писали:


F>Но что-то мне не очень верится, что я полностью победил проблему, ибо не понимаю её, такое не очень приятное ощущение, что она проявится снова в самый неприятный момент


F>PS. Подумал было, что может быть причина в переупорядочении последовательности команд компилятором, о которой не так давно писал remark, поставил вместо "someGlobaldata = 0;" мьютекс — не помогло


Может дело в этом:

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.

Re[3]: нехороший malloc, нужны телепаты
От: frogkiller Россия  
Дата: 15.10.08 11:33
Оценка:
Здравствуйте, 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.
Курица — это инструмент, с помощью которого одно яйцо производит другие.
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.