Ошибка сегментации в многопоточной программе и неполная информация о трассировке GDB - PullRequest
0 голосов
/ 30 октября 2019

Я пишу программу, которая использует как потоки ОС, так и пользовательские потоки (волокна, я написал эту пользовательскую программу Threading с переключением контекста на ассемблере). Проблема в том, что программа иногда заканчивается ошибкой сегментации, но иногда это не так.

Проблема связана с тем, что вызывается функция с недопустимыми аргументами, которые не должны вызываться. Я думаю, что обратная трассировка gdb не дает правильной информации. Вот вывод моей программы gdb

#0  0x0000000000000000 in ?? ()
#1  0x0000555555555613 in thread_entry (fn=0x0, arg=0x0) at userThread2.cpp:243
#2  0x000055555555c791 in start_thread () at contextSwitch2.s:57
#3  0x0000000000000000 in ?? ()

fn - это функция, которую я хочу запустить как пользовательский поток, arg - переданный аргументк этой функции. У меня есть функция Spawn в коде пользовательской библиотеки потоков, которая помещает два аргумента (fn и arg) и указатель на start_thread в стеке и, таким образом, вызывается start_thread, функция сборки, которая вызывает функцию c ++ thread_entry для вызова функции fnс аргументами arg.

Я не ожидаю вызова start_thread или thread_entry в точке ошибки, поэтому я не уверен, как вызывается start_thread. Даже если он вызывается, тогда Spawn () должен был вызвать start_thread, поскольку это единственная функция, которая вызывает start_thread. Но Spawn не отображается в gtb backtrace.

В некоторых онлайн-публикациях упоминается возможность повреждения стека или что-то подобное в результате ошибки, и они предписывают использование «record btrace pt». Я потратил много времени на настройку поддержки Intel Btrace PT в ядре / GDB, но я не смог настроить его, поэтому я не иду по этому пути.

Вот ссылка на мой код с инструкциями по компиляции:https://github.com/smartWaqar/userThreading

1 Ответ

1 голос
/ 31 октября 2019

Я установил точку останова на thread_entry и заметил:

...
[Thread 0x7ffff7477700 (LWP 203995) exited]
parentId: 1 
OST 1 Hello A0 on CPU 2 
current_thread_num 0 next_thread_num 1
After Thread Exit 
After changeOSThread
OST 1 Hello C1 on CPU 2 ---------------
Before changeOSThread
**************** In changeOSThread **************
current_thread_num 1 next_thread_num 2

Thread 3 "a.out" hit Breakpoint 1, thread_entry (fn=0x0, arg=0x0) at userThread2.cpp:243
243     fn(arg) ;
(gdb) bt 
#0  thread_entry (fn=0x0, arg=0x0) at userThread2.cpp:243
#1  0x000055555555c181 in start_thread () at context.s:57
#2  0x0000000000000000 in ?? ()

Выводы:

  1. GDB равен , что дает вам правильную трассировку стека аварийного завершения.
  2. Вы делаете на самом деле, звоните thread_entry с fn==0, что, конечно, быстро приводит к сбою.
  3. Происходит что-то колоритное, поскольку этого не происходиткаждый раз.

Даже если он вызывается, Spawn () должен был вызвать start_thread, поскольку это единственная функция, которая вызывает start_thread

Я наблюдалследующий «вызов» strart_thread:

Thread 2 "a.out" hit Breakpoint 1, start_thread () at context.s:53
53    push    %rbp
(gdb) bt 
#0  start_thread () at context.s:53
#1  0x0000555555555e4f in changeOSThread (parentId=<error reading variable>) at t.cc:196
#2  0x0000000000000000 in ?? ()

Так что я думаю, что ваша ментальная модель того, кто называет start_thread, неверна.

Это слишком большой код для меня, чтобыпосмотри на. Если вам нужна дополнительная помощь, уменьшите тестовый набор до минимума.

...