This is the mail archive of the
gdb-patches@sourceware.org
mailing list for the GDB project.
Re: [PATCH 1/2] avoid infinite loop with bad debuginfo
- From: Pedro Alves <palves at redhat dot com>
- To: Tom Tromey <tromey at redhat dot com>
- Cc: gdb-patches at sourceware dot org
- Date: Fri, 22 Nov 2013 14:31:28 +0000
- Subject: Re: [PATCH 1/2] avoid infinite loop with bad debuginfo
- Authentication-results: sourceware.org; auth=none
- References: <1384375873-32160-1-git-send-email-tromey at redhat dot com> <1384375873-32160-2-git-send-email-tromey at redhat dot com> <52850730 dot 1060109 at redhat dot com> <87d2lxpo1l dot fsf at fleche dot redhat dot com>
On 11/18/2013 06:23 PM, Tom Tromey wrote:
>>> + if (VALUE_LVAL (new_val) == lval_register
>>> + && value_lazy (new_val)
>>> + && frame_id_eq (VALUE_FRAME_ID (new_val), last_frame_id))
>
> Pedro> I think this should also check the regnum:
>
> Barf. I have a memory of actually writing that. False memory I guess.
> Sigh.
Don't sigh. :-) I now believe the regnum check would be wrong.
This shouldn't return any register of the same frame.
WDYT of adjusting the patch like this?
------
From: Tom Tromey <tromey@redhat.com>
Subject: [PATCH] Detect lval_register handling infinite loop in
value_fetch_lazy.
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/value.c | 20 +++++++++++++++++++-
1 file changed, 19 insertions(+), 1 deletion(-)
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
--
1.7.11.7