17e05a9
http://sourceware.org/ml/gdb-patches/2010-02/msg00625.html
17e05a9
Subject: RFC: fix bug with std::terminate handler
17e05a9
17e05a9
I would appreciate comments on this patch.
17e05a9
17e05a9
This comes from an automatically-reported bug in the Red Hat bugzilla:
17e05a9
17e05a9
    https://bugzilla.redhat.com/show_bug.cgi?id=562975
17e05a9
17e05a9
call_function_by_hand installs a momentary breakpoint on std::terminate,
17e05a9
and then deletes it later.  However, this can cause a double deletion of
17e05a9
the breakpoint.  In the bug, the called function is dlopen, which causes
17e05a9
gdb to enter solib_add, which calls breakpoint_re_set, deleting the
17e05a9
momentary breakpoint.
17e05a9
17e05a9
This fix works by creating the momentary breakpoint with an internal
17e05a9
breakpoint number, and then trying to delete the breakpoint by number.
17e05a9
17e05a9
This bug does not always manifest in a crash.  In fact, I couldn't make
17e05a9
it crash here, but I could observe the problem under valgrind.
17e05a9
17e05a9
Built and regtested on x86-64 (compile farm).  I also manually verified
17e05a9
it using valgrind.
17e05a9
17e05a9
I think this patch is mildly ugly, due to the introduction of
17e05a9
set_momentary_breakpoint_at_pc_with_number.  However, in the absence of
17e05a9
comments, I plan to check it in after a reasonable waiting period.
17e05a9
17e05a9
Tom
17e05a9
17e05a9
2010-02-25  Tom Tromey  <tromey@redhat.com>
17e05a9
17e05a9
	* infcall.c (do_delete_breakpoint_by_number): New function.
17e05a9
	(call_function_by_hand): Refer to momentary breakpoint by number.
17e05a9
	* breakpoint.h (set_momentary_breakpoint_at_pc_with_number):
17e05a9
	Declare.
17e05a9
	* breakpoint.c (set_momentary_breakpoint_at_pc_with_number): New
17e05a9
	function.
17e05a9
17e05a9
Index: gdb-7.0.1/gdb/breakpoint.c
17e05a9
===================================================================
17e05a9
--- gdb-7.0.1.orig/gdb/breakpoint.c	2010-03-12 00:26:46.000000000 +0100
17e05a9
+++ gdb-7.0.1/gdb/breakpoint.c	2010-03-12 00:26:54.000000000 +0100
17e05a9
@@ -5647,6 +5647,20 @@ set_momentary_breakpoint_at_pc (struct g
17e05a9
 
17e05a9
   return set_momentary_breakpoint (gdbarch, sal, null_frame_id, type);
17e05a9
 }
17e05a9
+
17e05a9
+/* Like set_momentary_breakpoint_at_pc, but ensure that the new
17e05a9
+   breakpoint has a number.  */
17e05a9
+
17e05a9
+struct breakpoint *
17e05a9
+set_momentary_breakpoint_at_pc_with_number (struct gdbarch *gdbarch,
17e05a9
+					    CORE_ADDR pc,
17e05a9
+					    enum bptype type)
17e05a9
+{
17e05a9
+  struct breakpoint *result = set_momentary_breakpoint_at_pc (gdbarch, pc,
17e05a9
+							      type);
17e05a9
+  result->number = internal_breakpoint_number--;
17e05a9
+  return result;
17e05a9
+}
17e05a9
 
17e05a9
 
17e05a9
 /* Tell the user we have just set a breakpoint B.  */
17e05a9
Index: gdb-7.0.1/gdb/breakpoint.h
17e05a9
===================================================================
17e05a9
--- gdb-7.0.1.orig/gdb/breakpoint.h	2010-03-12 00:26:46.000000000 +0100
17e05a9
+++ gdb-7.0.1/gdb/breakpoint.h	2010-03-12 00:26:54.000000000 +0100
17e05a9
@@ -741,6 +741,9 @@ extern struct breakpoint *set_momentary_
17e05a9
 extern struct breakpoint *set_momentary_breakpoint_at_pc
17e05a9
   (struct gdbarch *, CORE_ADDR pc, enum bptype type);
17e05a9
 
17e05a9
+extern struct breakpoint *set_momentary_breakpoint_at_pc_with_number
17e05a9
+  (struct gdbarch *, CORE_ADDR pc, enum bptype type);
17e05a9
+
17e05a9
 extern struct breakpoint *clone_momentary_breakpoint (struct breakpoint *bpkt);
17e05a9
 
17e05a9
 extern void set_ignore_count (int, int, int);
17e05a9
Index: gdb-7.0.1/gdb/infcall.c
17e05a9
===================================================================
17e05a9
--- gdb-7.0.1.orig/gdb/infcall.c	2010-03-12 00:26:46.000000000 +0100
17e05a9
+++ gdb-7.0.1/gdb/infcall.c	2010-03-12 00:27:31.000000000 +0100
17e05a9
@@ -410,6 +410,18 @@ run_inferior_call (struct thread_info *c
17e05a9
   return e;
17e05a9
 }
17e05a9
 
17e05a9
+/* A cleanup function that deletes a breakpoint, if it still exists,
17e05a9
+   given the breakpoint's number.  */
17e05a9
+
17e05a9
+static void
17e05a9
+do_delete_breakpoint_by_number (void *arg)
17e05a9
+{
17e05a9
+  int *num = arg;
17e05a9
+  struct breakpoint *bp = get_breakpoint (*num);
17e05a9
+  if (bp)
17e05a9
+    delete_breakpoint (bp);
17e05a9
+}
17e05a9
+
17e05a9
 /* All this stuff with a dummy frame may seem unnecessarily complicated
17e05a9
    (why not just save registers in GDB?).  The purpose of pushing a dummy
17e05a9
    frame which looks just like a real frame is so that if you call a
17e05a9
@@ -447,7 +459,8 @@ call_function_by_hand (struct value *fun
17e05a9
   struct cleanup *args_cleanup;
17e05a9
   struct frame_info *frame;
17e05a9
   struct gdbarch *gdbarch;
17e05a9
-  struct breakpoint *terminate_bp = NULL;
17e05a9
+  int terminate_bp_num = 0;
17e05a9
+  CORE_ADDR terminate_bp_addr = 0;
17e05a9
   struct minimal_symbol *tm;
17e05a9
   struct cleanup *terminate_bp_cleanup = NULL;
17e05a9
   ptid_t call_thread_ptid;
17e05a9
@@ -764,8 +777,13 @@ call_function_by_hand (struct value *fun
17e05a9
        struct minimal_symbol *tm = lookup_minimal_symbol  ("std::terminate()",
17e05a9
 							   NULL, NULL);
17e05a9
        if (tm != NULL)
17e05a9
-	   terminate_bp = set_momentary_breakpoint_at_pc
17e05a9
+	 {
17e05a9
+	   struct breakpoint *bp;
17e05a9
+	   bp = set_momentary_breakpoint_at_pc_with_number
17e05a9
 	     (gdbarch, SYMBOL_VALUE_ADDRESS (tm),  bp_breakpoint);
17e05a9
+	   terminate_bp_num = bp->number;
17e05a9
+	   terminate_bp_addr = bp->loc->address;
17e05a9
+	 }
17e05a9
      }
17e05a9
 
17e05a9
   /* Everything's ready, push all the info needed to restore the
17e05a9
@@ -779,8 +797,9 @@ call_function_by_hand (struct value *fun
17e05a9
   discard_cleanups (inf_status_cleanup);
17e05a9
 
17e05a9
   /* Register a clean-up for unwind_on_terminating_exception_breakpoint.  */
17e05a9
-  if (terminate_bp)
17e05a9
-    terminate_bp_cleanup = make_cleanup_delete_breakpoint (terminate_bp);
17e05a9
+  if (terminate_bp_num != 0)
17e05a9
+    terminate_bp_cleanup = make_cleanup (do_delete_breakpoint_by_number,
17e05a9
+					 &terminate_bp_num);
17e05a9
 
17e05a9
   /* - SNIP - SNIP - SNIP - SNIP - SNIP - SNIP - SNIP - SNIP - SNIP -
17e05a9
      If you're looking to implement asynchronous dummy-frames, then
17e05a9
@@ -946,9 +965,9 @@ When the function is done executing, GDB
17e05a9
 		 in an inferior function call. Rewind, and warn the
17e05a9
 		 user.  */
17e05a9
 
17e05a9
-	      if (terminate_bp != NULL
17e05a9
+	      if (terminate_bp_num != 0
17e05a9
 		  && (inferior_thread()->stop_bpstat->breakpoint_at->address
17e05a9
-		      == terminate_bp->loc->address))
17e05a9
+		      == terminate_bp_addr))
17e05a9
 		{
17e05a9
 		  /* We must get back to the frame we were before the
17e05a9
 		     dummy call.  */
17e05a9
@@ -997,7 +1016,7 @@ When the function is done executing, GDB
17e05a9
 
17e05a9
   /* If we get here and the std::terminate() breakpoint has been set,
17e05a9
      it has to be cleaned manually.  */
17e05a9
-  if (terminate_bp)
17e05a9
+  if (terminate_bp_num != 0)
17e05a9
     do_cleanups (terminate_bp_cleanup);
17e05a9
 
17e05a9
   /* If we get here the called FUNCTION ran to completion,