aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTom Tromey <tromey@redhat.com>2013-11-22 17:38:44 +0000
committerPedro Alves <palves@redhat.com>2013-11-22 17:38:44 +0000
commit6eeee81c8e59511962bdd83df5e7785bfdf871d2 (patch)
tree665dbcbe078b8f2ba0878597126ef8eac72d0f66
parent0cb112f7400187275da81a05a9ad0534f1430139 (diff)
downloadfsf-binutils-gdb-6eeee81c8e59511962bdd83df5e7785bfdf871d2.zip
fsf-binutils-gdb-6eeee81c8e59511962bdd83df5e7785bfdf871d2.tar.gz
fsf-binutils-gdb-6eeee81c8e59511962bdd83df5e7785bfdf871d2.tar.bz2
Detect infinite loop in value_fetch_lazy's lval_register handling.
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.
-rw-r--r--gdb/ChangeLog7
-rw-r--r--gdb/value.c20
2 files changed, 26 insertions, 1 deletions
diff --git a/gdb/ChangeLog b/gdb/ChangeLog
index 07c8efd..1260b5c 100644
--- a/gdb/ChangeLog
+++ b/gdb/ChangeLog
@@ -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>
diff --git a/gdb/value.c b/gdb/value.c
index 8c263ea..da7778f 100644
--- a/gdb/value.c
+++ b/gdb/value.c
@@ -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