Что вызвало таинственную повторяющуюся запись в моем стеке? - PullRequest
3 голосов
/ 29 октября 2009

Я расследую тупиковую ошибку. Я взял ядро ​​с gcore и обнаружил, что одна из моих функций, похоже, вызвала себя - хотя она не делает рекурсивный вызов функции.

Вот фрагмент стека из GDB:

Thread 18 (Thread 4035926944 (LWP 23449)):
#0  0xffffe410 in __kernel_vsyscall ()
#1  0x005133de in __lll_mutex_lock_wait () from /lib/tls/libpthread.so.0
#2  0x00510017 in _L_mutex_lock_182 () from /lib/tls/libpthread.so.0
#3  0x080d653c in ?? ()
#4  0xf7c59480 in ?? () from LIBFOO.so
#5  0x081944c0 in ?? ()
#6  0x081944b0 in ?? ()
#7  0xf08f3b38 in ?? ()
#8  0xf7c3b34c in FOO::Service::releaseObject ()
   from LIBFOO.so
#9  0xf7c3b34c in FOO::Service::releaseObject ()
   from LIBFOO.so
#10 0xf7c36006 in FOO::RequesterImpl::releaseObject ()
   from LIBFOO.so
#11 0xf7e2afbf in BAR::BAZ::unsubscribe (this=0x80d0070, sSymbol=@0xf6ded018)
    at /usr/lib/gcc/x86_64-redhat-linux/3.4.6/../../../../include/c++/3.4.6/bits/stl_tree.h:176
...more stack

Я исключил некоторые имена: FOO & BAR - это пространства имен.BAZ - это класс.

Интересная часть - это # ​​8 и # 9, вызов Service::releaseObject(). Эта функция не вызывает сама себя и не вызывает никаких функций, которые ее вызывают ... она не рекурсивная. Почему тогда он появляется в стеке дважды?

Это артефакт, созданный отладчиком, или он может быть реальным?

Вы заметите, что внутренний вызов ожидает мьютекса - я думаю, что это может быть моим тупиком. Service::releaseObject() блокирует мьютекс, поэтому, если он волшебным образом телепортируется обратно внутрь себя, то наверняка может возникнуть тупик.

Некоторый фон:

Это скомпилировано с использованием g ++ v3.4.6 на RHEL4. Это 64-битная ОС, но это 32-битный код, скомпилированный с -m32. Оптимизировано при -O3. Я не могу гарантировать, что код приложения был скомпилирован с теми же параметрами, что и код LIBFOO.

Класс Service не имеет виртуальных функций, поэтому нет vtable. Класс RequesterImpl наследуется от полностью виртуального интерфейса, поэтому у него есть vtable.

Ответы [ 2 ]

4 голосов
/ 29 октября 2009

Стеки трассировки на x86 ненадежны при любом уровне оптимизации: -O1 и более поздние разрешения -fomit-frame-pointer.

3 голосов
/ 30 октября 2009

Причина, по которой вы получаете "плохой" стек, заключается в том, что __lll_mutex_lock_wait имеет неверный дескриптор раскрутки (он написан в сборке с ручным кодированием). Я считаю, что это было исправлено несколько недавно (в 2008 году), но не могу найти точный патч.

Как только разматыватель стека GDB выходит из равновесия, он создает фиктивные кадры (от # 2 до # 8), но в конечном итоге натыкается на кадр, который использует указатель кадра, и производит правильную трассировку стека для остальной части стека .

...