watch_command_1: Fix dangling frame access
authorPedro Alves <palves@redhat.com>
Thu, 13 Apr 2017 15:15:34 +0000 (16:15 +0100)
committerPedro Alves <palves@redhat.com>
Thu, 13 Apr 2017 15:15:34 +0000 (16:15 +0100)
While working on some changes to switch_to_thread, I inadvertently
make switch_to_thread call reinit_frame_cache more frequently, even
when the thread didn't change.  This exposed a latent bug in
watch_command_1, where we're referencing a frame after
creating/inserting breakpoints, which potentially calls
reinit_frame_cache if it needs to install breakpoints with a different
thread selected.

Handle this similarly to how it's already handled in other similar
cases.  I.e., save any frame-related information we might need before
creating a breakpoint.

gdb/ChangeLog:
2017-04-13  Pedro Alves  <palves@redhat.com>

* breakpoint.c (watch_command_1): Save watchpoint-frame info
before calling create_internal_breakpoint.

gdb/ChangeLog
gdb/breakpoint.c

index 90ed21caff54c10f5cf349a68d0b877c0cf87270..acf59e5abb813bc35fd3a0c9e18d03e357f65836 100644 (file)
@@ -1,3 +1,8 @@
+2017-04-13  Pedro Alves  <palves@redhat.com>
+
+       * breakpoint.c (watch_command_1): Save watchpoint-frame info
+       before calling create_internal_breakpoint.
+
 2017-04-13  Pedro Alves  <palves@redhat.com>
 
        * fork-child.c (execv_argv): New class.
index 1fe4eb08c5d78cd5109f70c601d605a2a88fe852..4940ec271b7529a1b36aa3f5db6a8c99df933482 100644 (file)
@@ -11062,7 +11062,6 @@ watch_command_1 (const char *arg, int accessflag, int from_tty,
   const struct block *exp_valid_block = NULL, *cond_exp_valid_block = NULL;
   struct value *val, *mark, *result;
   int saved_bitpos = 0, saved_bitsize = 0;
-  struct frame_info *frame;
   const char *exp_start = NULL;
   const char *exp_end = NULL;
   const char *tok, *end_tok;
@@ -11240,35 +11239,44 @@ watch_command_1 (const char *arg, int accessflag, int from_tty,
   if (*tok)
     error (_("Junk at end of command."));
 
-  frame = block_innermost_frame (exp_valid_block);
+  frame_info *wp_frame = block_innermost_frame (exp_valid_block);
+
+  /* Save this because create_internal_breakpoint below invalidates
+     'wp_frame'.  */
+  frame_id watchpoint_frame = get_frame_id (wp_frame);
 
   /* If the expression is "local", then set up a "watchpoint scope"
      breakpoint at the point where we've left the scope of the watchpoint
      expression.  Create the scope breakpoint before the watchpoint, so
      that we will encounter it first in bpstat_stop_status.  */
-  if (exp_valid_block && frame)
+  if (exp_valid_block != NULL && wp_frame != NULL)
     {
-      if (frame_id_p (frame_unwind_caller_id (frame)))
+      frame_id caller_frame_id = frame_unwind_caller_id (wp_frame);
+
+      if (frame_id_p (caller_frame_id))
        {
+         gdbarch *caller_arch = frame_unwind_caller_arch (wp_frame);
+         CORE_ADDR caller_pc = frame_unwind_caller_pc (wp_frame);
+
          scope_breakpoint
-           = create_internal_breakpoint (frame_unwind_caller_arch (frame),
-                                         frame_unwind_caller_pc (frame),
+           = create_internal_breakpoint (caller_arch, caller_pc,
                                          bp_watchpoint_scope,
                                          &momentary_breakpoint_ops);
 
+         /* create_internal_breakpoint could invalidate WP_FRAME.  */
+         wp_frame = NULL;
+
          scope_breakpoint->enable_state = bp_enabled;
 
          /* Automatically delete the breakpoint when it hits.  */
          scope_breakpoint->disposition = disp_del;
 
          /* Only break in the proper frame (help with recursion).  */
-         scope_breakpoint->frame_id = frame_unwind_caller_id (frame);
+         scope_breakpoint->frame_id = caller_frame_id;
 
          /* Set the address at which we will stop.  */
-         scope_breakpoint->loc->gdbarch
-           = frame_unwind_caller_arch (frame);
-         scope_breakpoint->loc->requested_address
-           = frame_unwind_caller_pc (frame);
+         scope_breakpoint->loc->gdbarch = caller_arch;
+         scope_breakpoint->loc->requested_address = caller_pc;
          scope_breakpoint->loc->address
            = adjust_breakpoint_address (scope_breakpoint->loc->gdbarch,
                                         scope_breakpoint->loc->requested_address,
@@ -11340,9 +11348,9 @@ watch_command_1 (const char *arg, int accessflag, int from_tty,
   else
     b->cond_string = 0;
 
-  if (frame)
+  if (frame_id_p (watchpoint_frame))
     {
-      w->watchpoint_frame = get_frame_id (frame);
+      w->watchpoint_frame = watchpoint_frame;
       w->watchpoint_thread = inferior_ptid;
     }
   else