Sources Bugzilla – Bug 9593
"next" command in a function that throws a C++ exception causes GDB to lose control of the inferior
Last modified: 2011-11-16 20:05:53 UTC
[Converted from Gnats 2488] Run the next command in a function that throws a C++ exception. The inferior is not stopped as described in next command help. The inferior continues until program exit, or an unrelated breakpoint triggers. Expectation is that the inferior should either stop in the first local variable destructor (if there is one) or in the matching catch exception handler (if there is one). Release: 6..8 Environment: Linux How-To-Repeat: The included test-case shows the behaviour. Step to func1, then run "next" from that function. The program will exit. It should stop in the the catch exception handler in this case.
Fix: Looking at next_command() it installed four momentary breakpoints (longjmp/siglongjmp/_longjnp/_siglongjmp) and resumes the inferior. C++ Exception handling does not use this method, but instead relies on dwarf register annotations and unwinding the stack and type-checking exception handlers. next command needs to account for methods other than longjmp.
For the record, this bug is fixed on archer-pmuldoon-next-over-throw2. It is waiting for some longjmp patches before submitting to gdb.
CVSROOT: /cvs/src Module name: src Changes by: tromey@sourceware.org 2010-12-09 16:09:55 Modified files: gdb : ChangeLog breakpoint.c breakpoint.h gdbthread.h infcmd.c inferior.h infrun.c thread.c gdb/testsuite : ChangeLog Added files: gdb/testsuite/gdb.cp: nextoverthrow.cc nextoverthrow.exp gdb/testsuite/gdb.java: jnpe.exp jnpe.java Log message: gdb PR c++/9593: * thread.c (clear_thread_inferior_resources): Call delete_longjmp_breakpoint. * infrun.c (handle_inferior_event): Handle exception breakpoints. (handle_inferior_event): Likewise. (insert_exception_resume_breakpoint): New function. (check_exception_resume): Likewise. * inferior.h (delete_longjmp_breakpoint_cleanup): Declare. * infcmd.c (delete_longjmp_breakpoint_cleanup): No longer static. (step_1): Set thread's initiating frame. (until_next_continuation): New function. (until_next_command): Support exception breakpoints. (finish_command_continuation): Delete longjmp breakpoint. (finish_forward): Support exception breakpoints. * gdbthread.h (struct thread_info) <initiating_frame>: New field. * breakpoint.h (enum bptype) <bp_exception, bp_exception_resume, bp_exception_master>: New constants. (struct bpstat_what) <is_longjmp>: New field. (set_longjmp_breakpoint): Update. * breakpoint.c (create_exception_master_breakpoint): New function. (update_breakpoints_after_exec): Handle bp_exception_master. Call create_exception_master_breakpoint. (print_it_typical): Handle bp_exception_master, bp_exception. (bpstat_stop_status): Handle bp_exception_master. (bpstat_what): Handle bp_exception_master, bp_exception, bp_exception_resume. (bptype_string): Likewise. (print_one_breakpoint_location): Likewise. (allocate_bp_location): Likewise. (set_longjmp_breakpoint): Handle exception breakpoints. Change interface. (delete_longjmp_breakpoint): Handle exception breakpoints. (mention): Likewise. (struct until_break_command_continuation_args) <thread_num>: New field. (until_break_command_continuation): Call delete_longjmp_breakpoint. (until_break_command): Support exception breakpoints. (delete_command): Likewise. (breakpoint_re_set_one): Likewise. (breakpoint_re_set): Likewise. gdb/testuite * gdb.java/jnpe.java: New file. * gdb.java/jnpe.exp: New file. * gdb.cp/nextoverthrow.exp: New file. * gdb.cp/nextoverthrow.cc: New file. Patches: http://sourceware.org/cgi-bin/cvsweb.cgi/src/gdb/ChangeLog.diff?cvsroot=src&r1=1.12367&r2=1.12368 http://sourceware.org/cgi-bin/cvsweb.cgi/src/gdb/breakpoint.c.diff?cvsroot=src&r1=1.518&r2=1.519 http://sourceware.org/cgi-bin/cvsweb.cgi/src/gdb/breakpoint.h.diff?cvsroot=src&r1=1.127&r2=1.128 http://sourceware.org/cgi-bin/cvsweb.cgi/src/gdb/gdbthread.h.diff?cvsroot=src&r1=1.58&r2=1.59 http://sourceware.org/cgi-bin/cvsweb.cgi/src/gdb/infcmd.c.diff?cvsroot=src&r1=1.270&r2=1.271 http://sourceware.org/cgi-bin/cvsweb.cgi/src/gdb/inferior.h.diff?cvsroot=src&r1=1.146&r2=1.147 http://sourceware.org/cgi-bin/cvsweb.cgi/src/gdb/infrun.c.diff?cvsroot=src&r1=1.460&r2=1.461 http://sourceware.org/cgi-bin/cvsweb.cgi/src/gdb/thread.c.diff?cvsroot=src&r1=1.124&r2=1.125 http://sourceware.org/cgi-bin/cvsweb.cgi/src/gdb/testsuite/ChangeLog.diff?cvsroot=src&r1=1.2525&r2=1.2526 http://sourceware.org/cgi-bin/cvsweb.cgi/src/gdb/testsuite/gdb.cp/nextoverthrow.cc.diff?cvsroot=src&r1=NONE&r2=1.1 http://sourceware.org/cgi-bin/cvsweb.cgi/src/gdb/testsuite/gdb.cp/nextoverthrow.exp.diff?cvsroot=src&r1=NONE&r2=1.1 http://sourceware.org/cgi-bin/cvsweb.cgi/src/gdb/testsuite/gdb.java/jnpe.exp.diff?cvsroot=src&r1=NONE&r2=1.1 http://sourceware.org/cgi-bin/cvsweb.cgi/src/gdb/testsuite/gdb.java/jnpe.java.diff?cvsroot=src&r1=NONE&r2=1.1
*** Bug 8519 has been marked as a duplicate of this bug. ***
Fixed in cvs.
Created attachment 6056 [details] testcase includes 3 c++ files The attachmnent contains a CDivide class ,which simpley implements a method a/b. However,if b equals zero ,an exception is thrown . This class is compiled as a dynamic linked library. And main.cpp loads the library to use its methods. When debugging main.cpp,if step to "pCd->doDivide()", then run "next" command ,gdb will lose control of the inferor and the program will exit.
I am afraid this bug has not been fixed completely. GDB now do have a better performance for "next" command when exceptions are thrown, but not for all the cases. If an exception is throw from a dynamic loaded library, GDB doesn't behave any better ,GDB will still lose control of inferior and display more error information. How-To-Repeat: The test case included in attachment shows the behavior. Step to "pCd->doDivide()", then run "next" command. The program will exit. Environment: GDB 7.3 accompany with GCC 4.6.1 OS: Ubuntu 11.10
I had to modify your program to get it to compile and link. It might help if you posted the exact commands you used to do this; maybe as a Makefile. Meanwhile, the feature still works for me, even with the modified program: Breakpoint 1, main () at main.cpp:27 27 if((errMsg=dlerror())!=NULL) (gdb) n 33 result = FuncCreator(10, 0); (gdb) n 0x0000000000400950 35 catch(int) (gdb) n 37 printf("Catch an exception\n"); In my modified version, the call to FuncCreator throws. I'm using Fedora 15. It is possible that the problem is a system problem, as this feature relies on a system feature in order to work. However, if it works for you in other cases, then it is not too likely that this is the problem.
Thanks Tom very much. Compile commands that I use are(g++ 4.6.1): g++ -g -shared -fpic -o libDiv.so Divide.h Divide.cpp g++ -g -o main main.cpp Divide.h -lDiv -ldl And a snap sort of the debugging is as below: 32 if ( pCd == NULL ) (gdb) n 38 int result=0; (gdb) n 41 result=pCd->doDivide(); (gdb) n Catch an exception result=0 [Inferior 1 (process 2040) exited normally] warning: Error removing breakpoint 0 warning: Error removing breakpoint 0 warning: Error removing breakpoint 0 And as with the test case(simplest_next_fail.cxx ) provided by Phil Muldoon,the debugging process is something like: (compile command is: g++ -g -o sp simplest_next_fail.cxx) (gdb) r Starting program: /home/george/sp Breakpoint 1, main () at simplest_next_fail.cxx :17 17 func1(); (gdb) n Should regain control of inferior here. 27 cout << "Exiting the program." << endl; (gdb) n Exiting the program. 28 return 0; (gdb) I think gdb should regain control of inferior at line: 23 cout << "Should regain control of inferior here." << endl; However, as a matter of fact gdb regains control at line: 27 cout << "Exiting the program." << endl; I don't know if that is normal. But at least gdb does not lose control this time.
I tried your test case, using gdb 7.3, and it worked fine here. I am beginning to suspect a system problem. Do you have debuginfo installed for libgcc.so?
Yes,I have. Our project is something about auto debugging using gdb. Now, I have transfered the project to Fedora 15,and it works well on Fedora. Thanks for your time and effort.
Sounds like a distro bug then.