LINUX.ORG.RU

[C++][SIGSEGV]Помогите с отладкой

 


0

1

Отлаживаю kopete, который стабильно падает при каждом закрытии. Ловит сегфолт в деструкторе класса Client. Выкинул из деструктора всё - не помогло. Из членов у класса - только ClientPrivate* d;.

Класс наследуется от QObject.

Итак, пустой деструктор:

Dump of assembler code for function Client::~Client():
=> 0x00007fa293639900 <+0>:     push   %rbx
   0x00007fa293639901 <+1>:     mov    %rdi,%rbx
   0x00007fa293639904 <+4>:     callq  0x7fa293633dd0 <_ZN6ClientD1Ev@plt>
   0x00007fa293639909 <+9>:     mov    %rbx,%rdi
   0x00007fa29363990c <+12>:    pop    %rbx
   0x00007fa29363990d <+13>:    jmpq   0x7fa2936352f0 <_ZdlPv@plt>
End of assembler dump.

_ZdlPv - это обычный operator delete(void*). Что такое _ZN6ClientD1Ev - это тот же Client::~Client(). Падает в нём:

Dump of assembler code for function _ZN6ClientD1Ev@plt:
=> 0x00007fa293633dd0 <+0>:     jmpq   *0x2fb242(%rip)        # 0x7fa29392f018
   0x00007fa293633dd6 <+6>:     pushq  $0x41
   0x00007fa293633ddb <+11>:    jmpq   0x7fa2936339b0
End of assembler dump.
(gdb) disassemble 0x7fa29392f018
No function contains specified address.
(gdb) disassemble 0x7fa2936339b0
No function contains specified address.
(gdb) display/i $pc
1: x/i $pc
=> 0x7fa293633dd0 <_ZN6ClientD1Ev@plt>: jmpq   *0x2fb242(%rip)        # 0x7fa29392f018
(gdb) si
0x00007fa293633dd6 in Client::~Client () from /home/valentine/usr/lib/liboscar.so.1
1: x/i $pc
=> 0x7fa293633dd6 <_ZN6ClientD1Ev@plt+6>:       pushq  $0x41

Это как? Проигнорили jump? Идем на второй jmpq. Прыгаю внутрь:

(gdb) si
0x00007fa2936339b0 in ?? () from /home/valentine/usr/lib/liboscar.so.1
1: x/i $pc
=> 0x7fa2936339b0:      pushq  0x2fb44a(%rip)        # 0x7fa29392ee00
(gdb) si
0x00007fa2936339b6 in ?? () from /home/valentine/usr/lib/liboscar.so.1
1: x/i $pc
=> 0x7fa2936339b6:      jmpq   *0x2fb44c(%rip)        # 0x7fa29392ee08
(gdb) si
_dl_runtime_resolve () at ../sysdeps/x86_64/dl-trampoline.S:30
1: x/i $pc
=> 0x7fa2abf862c0 <_dl_runtime_resolve>:        sub    $0x38,%rsp

И т.д. и попадаю в libfam, откуда выхожу назад в ZN6ClientD1Ev (по более ранему адресу, чем был там раньше) и попадаю в SIGSEGV:

#0  0x000000000000000b in ?? () at /usr/include/qt4/QtCore/qlist.h:494
#1  0x00007fa293639909 in Client::~Client (this=0x2a95560, __in_chrg=<value optimized out>)
    at /home/valentine/tmp/1/kdenetwork-4.6.1/kopete/protocols/oscar/liboscar/client.cpp:222

В 1-ом фрейме видно, что я и не выходил из _ZN6ClientD1Ev, а словил лажу там.

Может кто подскажет, где может быть проблема?

★★★★★

Последнее исправление: Pavval (всего исправлений: 2)

Что такое _ZN6ClientD1Ev - хз. C++filt не распарсил.


% c++filt -n _ZN6ClientD1Ev
Client::~Client()

anonymous
()
Ответ на: комментарий от anonymous

% c++filt -n _ZN6ClientD1Ev
Client::~Client()

Балин... :) Я где-то неясно как потерял букву вимени и потому искал _Z6ClientD1Ev@plt (без N). Теперь понятно. Обновлю пост.

Pavval ★★★★★
() автор топика
Ответ на: комментарий от ratatosk

/usr/include/qt4/QtCore/qlist.h:494

Посмотри, что это за функция кстати - может наведет на мысли.

Начало QList<>::append() - совсем не в тему. Списков и рядом нет.

Pavval ★★★★★
() автор топика
Ответ на: комментарий от ratatosk

Попробуй valgrind'ом прогнать, скорее всего либо в освобожденную память лезет, либо просто мимо.

valgrind не совсем шарю. Если просто запустить valgrind kopete, то получу:

kopete(19957)/kopete (oscar - raw protocol) ICQAccount::~ICQAccount: CLIENT: Deleting from account at address  336382448
==19957== Warning: invalid file descriptor 527917808 in syscall close()
==19957== Use of uninitialised value of size 8
==19957==    at 0xEEA783F: Client::~Client() (in /usr/lib/libfam.so.0.0.0)
==19957==    by 0x141EC03F: ???
==19957== 
==19957== Jump to the invalid address stated on the next line
==19957==    at 0xB: ???
==19957==  Address 0xb is not stack'd, malloc'd or (recently) free'd
==19957== 
KCrash: Application 'kopete' crashing...
KCrash: Attempting to start /usr/lib/kde4/libexec/drkonqi from kdeinit

И не особо что понятно - какой еще close()...

Следуя логике я должен попадать в деструктор QObject (как базового класса). Там есть список child'ов - как раз QList<>. Надо подумать.

Pavval ★★★★★
() автор топика
Ответ на: комментарий от Pavval

Списков и рядом нет.

Как бы его тогда туда занесло? Есть, конечно, шанс, что это в результате порчи стека адрес там такой сформировался, но это вряд ли. Да и valgrind это тоже умеет проверять.

ratatosk
()
Ответ на: комментарий от ratatosk

А что именно проверить? Я вообще не догоняю, с какого в классе, который даже к ФС не обращается libfam. И да - деструктор же пустой, есть разве что деструктор QObject, но если бы это было в нем, то это было бы видно в bt (а он показывает ~Client).

Pavval ★★★★★
() автор топика
Ответ на: комментарий от dt1

Погляжу, что-то было, но среди отладочного мусора kopete (его просто туча) было сложно что-то искать. Вечером отпишусь.

Pavval ★★★★★
() автор топика
Ответ на: комментарий от dt1

Спасибо, учту. Читаю ман по valgrind:)

Pavval ★★★★★
() автор топика
Ответ на: комментарий от vertexua

Хотя вообще если либы большие, то valgrind начинает выдавать чудеса. В данном случае поможет, так как сегфолты он хорошо показывает. Но относительно утечек память, то на Qt или Gtk он часто их показывает. Видно они просто как-то особенно памятью управляют

vertexua ★★★★★
()
Ответ на: комментарий от vertexua

Ты тред читал? Я уже даже по асму гулял и не смог осознать. В сорцам ты тупо увидишь, что падает в пустом деструкторе.

Pavval ★★★★★
() автор топика
Ответ на: комментарий от Pavval

Да, что-то я туплю под вечер. Так оно всегда на ЛОРе, тред не читал, но осуждаю. Вообще это подробно смотреть надо, и не только в том месте. libfam там вообще скорее всего не в теме, там могла бы торчать другая любая библиотека. Интерестно бы пособирать с другими опциями и посмотреть не выскочит ли другая. Если выскочит, то просто серьезно этот класс исследовать, возможно на какую-то пустую заглушку заменить. Пока не понимаешь где проблема, можно глупый «бинарный поиск» сделать. Закоментировал часть логики. Проблема исчезла: да, нет? Ну это тоже тупо делать нельзя, надо хорошо выбирать какую часть отключать.

vertexua ★★★★★
()
Ответ на: комментарий от vertexua

Я только что дошел вот до чего: если сразу после

d->engine = new Client(this);

сделать

delete d->engine;

То всё так же валится. Так что проблема локализована и я уже смело могу отрубать куски кода, не беспокоясь о том, что похерю логику. Короче сейчас найти причину уже дело техники.

Pavval ★★★★★
() автор топика

Подобные чудесные трейсы у меня получались, когда я пытался QObject'ы на стеке создавать, а их кто-то по deleteLater убивал. После чего прога падала где угодно, но не в месте, где было вызвано удаление этого самого объекта. В общем подозреваю, что где-то здесь, а точнее не очень далеко от этого деструктора происходит именно это! У меня тоже падало на вызове деструктора, причем совершенно не того класса, который на стеке создавался.

Gorthauer ★★★★★
()
Ответ на: комментарий от Pavval

Сейчас веселее: Client с пустым конструктором тоже падает. Подтверждается повреждение памяти (хотя и так было понятно).

Pavval ★★★★★
() автор топика
Ответ на: комментарий от Gorthauer

Малореально - проект-то немаленький.

И что-то не похоже: если бы деструктор какого-то объекта портил бы память, то этого не было бы в моем текущем случае, а именно при

«delete new Client(this);»

т.е. когда после создания объекта никто не может успеть испортить его память.

Но если заменить на

«delete new Client1(this);»

И определить фейковый Client1, то работает.

Pavval ★★★★★
() автор топика
Ответ на: комментарий от ratatosk

Вообще как-то много у вас там голых указателей и ручной работы с памятью. Неужели так производительность важна? В Qt же есть всякие QScopedPointer, QSharedPointer...

ratatosk
()
Ответ на: комментарий от ratatosk

delete new Client() падает даже если ~Client () {} ?

Да.

Вообще как-то много у вас там голых указателей и ручной работы с памятью. Неужели так производительность важна? В Qt же есть всякие QScopedPointer, QSharedPointer...

Это не у меня, это у них. Я только хочу, чтобы у меня kopete не падал:)

Pavval ★★★★★
() автор топика
Ответ на: комментарий от Pavval

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

ratatosk
()
Ответ на: комментарий от Pavval

И вообще, если из конструктора все убрать - проходит ли? Если да, то какая строчка замешана?

ratatosk
()
Ответ на: комментарий от ratatosk

Я убирал ВЕСЬ конструктор (т.е. делал его пустым, только вызов QObject::QObject) - ноль эмоций, всё то же падение. Дело скорее не в Client, видимо память портится извне. Только что же надо запортить, чтобы delete new валился?

Pavval ★★★★★
() автор топика
Ответ на: комментарий от Pavval

Структуры аллокатора. Но вообще странно, что valgrind этого не засекает - т.к. обычно это обычно запись за пределами выделенного блока или освобождение при помощи free указателя, который не был выделен malloc.

Вобщем, успехов, тут помочь я уже увы ничем не могу.

ratatosk
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.