Bug 9593 - "next" command in a function that throws a C++ exception causes GDB to lose control of the inferior
Summary: "next" command in a function that throws a C++ exception causes GDB to lose c...
Alias: None
Product: gdb
Classification: Unclassified
Component: c++ (show other bugs)
Version: 7.3
: P3 normal
Target Milestone: 7.3
Assignee: Tom Tromey
: 8519 (view as bug list)
Depends on:
Reported: 2008-08-01 15:18 UTC by Phil Muldoon
Modified: 2011-11-16 20:05 UTC (History)
3 users (show)

See Also:
Last reconfirmed:

simplest_next_fail.cxx (302 bytes, application/octet-stream)
, Phil Muldoon
testcase includes 3 c++ files (789 bytes, application/octet-stream)
2011-11-14 07:38 UTC, George

Note You need to log in before you can comment on or make changes to this bug.
Description Phil Muldoon 2008-08-01 15:18:02 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).



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.
Comment 1 Phil Muldoon 2008-08-01 15:18:02 UTC
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.
Comment 2 Tom Tromey 2010-07-28 20:52:46 UTC
For the record, this bug is fixed on archer-pmuldoon-next-over-throw2.
It is waiting for some longjmp patches before submitting to gdb.
Comment 3 cvs-commit@gcc.gnu.org 2010-12-09 16:10:01 UTC
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:
	PR c++/9593:
	* thread.c (clear_thread_inferior_resources): Call
	* 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
	(print_it_typical): Handle bp_exception_master, bp_exception.
	(bpstat_stop_status): Handle bp_exception_master.
	(bpstat_what): Handle bp_exception_master, bp_exception,
	(bptype_string): Likewise.
	(print_one_breakpoint_location): Likewise.
	(allocate_bp_location): Likewise.
	(set_longjmp_breakpoint): Handle exception breakpoints.  Change
	(delete_longjmp_breakpoint): Handle exception breakpoints.
	(mention): Likewise.
	(struct until_break_command_continuation_args) <thread_num>: New
	(until_break_command_continuation): Call
	(until_break_command): Support exception breakpoints.
	(delete_command): Likewise.
	(breakpoint_re_set_one): Likewise.
	(breakpoint_re_set): Likewise.
	* gdb.java/jnpe.java: New file.
	* gdb.java/jnpe.exp: New file.
	* gdb.cp/nextoverthrow.exp: New file.
	* gdb.cp/nextoverthrow.cc: New file.

Comment 4 Tom Tromey 2010-12-09 16:11:56 UTC
*** Bug 8519 has been marked as a duplicate of this bug. ***
Comment 5 Tom Tromey 2010-12-09 16:14:29 UTC
Fixed in cvs.
Comment 6 George 2011-11-14 07:38:35 UTC
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.
Comment 7 George 2011-11-14 07:43:39 UTC
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. 

The test case included in attachment shows the behavior. Step to "pCd->doDivide()", then run "next" command. The program will exit.  

GDB 7.3 accompany with GCC 4.6.1
OS: Ubuntu 11.10
Comment 8 Tom Tromey 2011-11-14 14:25:57 UTC
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

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.
Comment 9 George 2011-11-15 02:26:35 UTC
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
[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;

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.
Comment 10 Tom Tromey 2011-11-15 14:12:51 UTC
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?
Comment 11 George 2011-11-16 14:26:10 UTC
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.
Comment 12 Tom Tromey 2011-11-16 20:05:53 UTC
Sounds like a distro bug then.