Страницы

Поиск по вопросам

понедельник, 6 января 2020 г.

Как найти место, где бросается исключение в С++?

#cpp #debian #исключения #gcc


Падает приложение с эксепшеном, в бактрейсе (gdb) - системные вызовы. Есть какие-нибудь
варианты найти место, где бросается исключение?


  terminate called after throwing an instance of 'std::system_error'
  what():  Invalid argument


gcc 4.8, debian

Дамп: http://pastebin.com/ffX5mJqz
    


Ответы

Ответ 1



Просто напишите catch throw в gdb до запуска программы. После этого gdb будет останавливаться при каждом броске исключения в месте его возникновения. UPD: по поводу перехватывания исключений определенного типа. На моей платформе gdb при вызове catch throw просто ставит breakpoint на функцию __cxxabiv1::__cxa_throw. Это внутренняя функция, которая вызывается при броске исключения. Если присмотреться, в нее помимо прочего передается typeinfo о типе брошенного исключения. Поэтому можно просто поставить условие на breakpoint по значению этого параметра. Пример того, как получить стектрейс для исключения с типом std::invalid_argument: $ cat test.cc #include void foo() { throw std::invalid_argument("other_invalid_argument"); } int main() { try { throw std::invalid_argument("invalid_argument"); } catch (...) { } try { throw std::range_error("range_error"); } catch (...) { } foo(); } $ g++ -g -O0 ./test.cc $ ./a.out terminate called after throwing an instance of 'std::invalid_argument' what(): other_invalid_argument Aborted (core dumped) $ gdb --args ./a.out (gdb) catch throw Catchpoint 1 (throw) (gdb) r Starting program: /tmp/a.out Loading gdb's copy of v17 libstdc++ pretty-printers. Catchpoint 1 (exception thrown), __cxxabiv1::__cxa_throw (obj=0x603090, tinfo=0x6020d0 , dest=0x400ab0 ) at ../../../../src/libstdc++-v3/libsupc++/eh_throw.cc:62 62 ../../../../src/libstdc++-v3/libsupc++/eh_throw.cc: No such file or directory. (gdb) set $info=tinfo <-- запоминаем tinfo (gdb) cond 1 tinfo==$info <-- ставим условие на catchpoint (gdb) c Continuing. Catchpoint 1 (exception thrown), __cxxabiv1::__cxa_throw (obj=0x603090, tinfo=0x6020d0 , dest=0x400ab0 ) at ../../../../src/libstdc++-v3/libsupc++/eh_throw.cc:62 62 in ../../../../src/libstdc++-v3/libsupc++/eh_throw.cc (gdb) bt <-- интересующий нас стектрейс #0 __cxxabiv1::__cxa_throw (obj=0x603090, tinfo=0x6020d0 , dest=0x400ab0 ) at ../../../../src/libstdc++-v3/libsupc++/eh_throw.cc:62 #1 0x0000000000400c5f in foo () at ./test.cc:4 #2 0x0000000000400de9 in main () at ./test.cc:14 UPD2: придумал еще способ, правда он не работает для многопоточных програм. Можно создавать checkpoint при каждом броске исключения, а после того, как программа упадет, восстанавливаться с последнего checkpoint-а. Программа та же, что и выше: $ gdb --args ./a.out (gdb) catch throw Catchpoint 1 (throw) (gdb) commands 1 Type commands for breakpoint(s) 1, one per line. End with a line saying just "end". >checkpoint >c >end (gdb) r Starting program: /tmp/a.out Loading gdb's copy of v17 libstdc++ pretty-printers. Catchpoint 1 (exception thrown), __cxxabiv1::__cxa_throw (obj=0x603090, tinfo=0x6020d0 , dest=0x400ab0 ) at ../../../../src/libstdc++-v3/libsupc++/eh_throw.cc:62 62 ../../../../src/libstdc++-v3/libsupc++/eh_throw.cc: No such file or directory. Catchpoint 1 (exception thrown), __cxxabiv1::__cxa_throw (obj=0x603090, tinfo=0x6020b0 , dest=0x400a10 ) at ../../../../src/libstdc++-v3/libsupc++/eh_throw.cc:62 62 in ../../../../src/libstdc++-v3/libsupc++/eh_throw.cc Catchpoint 1 (exception thrown), __cxxabiv1::__cxa_throw (obj=0x603090, tinfo=0x6020d0 , dest=0x400ab0 ) at ../../../../src/libstdc++-v3/libsupc++/eh_throw.cc:62 62 in ../../../../src/libstdc++-v3/libsupc++/eh_throw.cc terminate called after throwing an instance of 'std::invalid_argument' what(): other_invalid_argument Program received signal SIGABRT, Aborted. 0x00007ffff7531cc9 in __GI_raise (sig=sig@entry=6) at ../nptl/sysdeps/unix/sysv/linux/raise.c:56 56 ../nptl/sysdeps/unix/sysv/linux/raise.c: No such file or directory. (gdb) info checkpoints 3 process 20315 at 0x7ffff7b348b0, file ../../../../src/libstdc++-v3/libsupc++/eh_throw.cc, line 62 2 process 20314 at 0x7ffff7b348b0, file ../../../../src/libstdc++-v3/libsupc++/eh_throw.cc, line 62 1 process 20313 at 0x7ffff7b348b0, file ../../../../src/libstdc++-v3/libsupc++/eh_throw.cc, line 62 * 0 process 20309 (main process) at 0x7ffff7531cc9, file ../nptl/sysdeps/unix/sysv/linux/raise.c, line 56 (gdb) restart 3 Switching to process 20315 #0 __cxxabiv1::__cxa_throw (obj=0x603090, tinfo=0x6020d0 , dest=0x400ab0 ) at ../../../../src/libstdc++-v3/libsupc++/eh_throw.cc:62 62 ../../../../src/libstdc++-v3/libsupc++/eh_throw.cc: No such file or directory. (gdb) bt #0 __cxxabiv1::__cxa_throw (obj=0x603090, tinfo=0x6020d0 , dest=0x400ab0 ) at ../../../../src/libstdc++-v3/libsupc++/eh_throw.cc:62 #1 0x0000000000400c5f in foo () at ./test.cc:4 #2 0x0000000000400de9 in main () at ./test.cc:14

Ответ 2



Если приложение падает в результате исключения, то можно его отловить посредством try-catch. Если же приложение падает, например, из-за сегфолта, то тогда только ищите ошибку посредством багтрейсинга. Хотя можно и корректно пытаться выйти используя сигналы.

Комментариев нет:

Отправить комментарий