Detect infinite loop in value_fetch_lazy's lval_register handling.
authorTom Tromey <tromey@redhat.com>
Fri, 22 Nov 2013 17:38:44 +0000 (17:38 +0000)
committerPedro Alves <palves@redhat.com>
Fri, 22 Nov 2013 17:38:44 +0000 (17:38 +0000)
If value_fetch_lazy loops infinitely while unwrapping lval_register
values, it means we either somehow ended up with two frames with the
same ID in the frame chain, or some code is trying to unwind behind
get_prev_frame's back (e.g., a frame unwind sniffer trying to unwind).
In any case, it should always be an internal error to end up in this
situation.

This patch adds a check and throws an internal error if the same frame
is returned.

2013-11-22  Tom Tromey  <tromey@redhat.com>
    Pedro Alves  <palves@redhat.com>

PR backtrace/16155
* value.c (value_fetch_lazy): Internal error if
get_frame_register_value returns the same register.

gdb/ChangeLog
gdb/value.c

index 07c8efd..1260b5c 100644 (file)
@@ -1,3 +1,10 @@
+2013-11-22  Tom Tromey  <tromey@redhat.com>
+           Pedro Alves  <palves@redhat.com>
+
+       PR backtrace/16155
+       * value.c (value_fetch_lazy): Internal error if
+       get_frame_register_value returns the same register.
+
 2013-11-22  Pedro Alves  <palves@redhat.com>
            Tom Tromey  <tromey@redhat.com>
 
index 8c263ea..da7778f 100644 (file)
@@ -3507,7 +3507,9 @@ value_fetch_lazy (struct value *val)
 
       while (VALUE_LVAL (new_val) == lval_register && value_lazy (new_val))
        {
-         frame = frame_find_by_id (VALUE_FRAME_ID (new_val));
+         struct frame_id frame_id = VALUE_FRAME_ID (new_val);
+
+         frame = frame_find_by_id (frame_id);
          regnum = VALUE_REGNUM (new_val);
 
          gdb_assert (frame != NULL);
@@ -3521,6 +3523,22 @@ value_fetch_lazy (struct value *val)
                                                   regnum, type));
 
          new_val = get_frame_register_value (frame, regnum);
+
+         /* If we get another lazy lval_register value, it means the
+            register is found by reading it from the next frame.
+            get_frame_register_value should never return a value with
+            the frame id pointing to FRAME.  If it does, it means we
+            either have two consecutive frames with the same frame id
+            in the frame chain, or some code is trying to unwind
+            behind get_prev_frame's back (e.g., a frame unwind
+            sniffer trying to unwind), bypassing its validations.  In
+            any case, it should always be an internal error to end up
+            in this situation.  */
+         if (VALUE_LVAL (new_val) == lval_register
+             && value_lazy (new_val)
+             && frame_id_eq (VALUE_FRAME_ID (new_val), frame_id))
+           internal_error (__FILE__, __LINE__,
+                           _("infinite loop while fetching a register"));
        }
 
       /* If it's still lazy (for instance, a saved register on the