diff options
author | Tom Tromey <tromey@redhat.com> | 2013-11-22 17:38:44 +0000 |
---|---|---|
committer | Pedro Alves <palves@redhat.com> | 2013-11-22 17:38:44 +0000 |
commit | 6eeee81c8e59511962bdd83df5e7785bfdf871d2 (patch) | |
tree | 665dbcbe078b8f2ba0878597126ef8eac72d0f66 | |
parent | 0cb112f7400187275da81a05a9ad0534f1430139 (diff) | |
download | gdb-6eeee81c8e59511962bdd83df5e7785bfdf871d2.zip gdb-6eeee81c8e59511962bdd83df5e7785bfdf871d2.tar.gz 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/ChangeLog | 7 | ||||
-rw-r--r-- | gdb/value.c | 20 |
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 |