From: Thiago Jung Bauermann <thiago.bauermann@linaro.org>
To: Tom de Vries <tdevries@suse.de>
Cc: Simon Marchi <simark@simark.ca>,
gdb-patches@sourceware.org, "Aktemur,
Tankut Baris" <tankut.baris.aktemur@intel.com>,
"Maciej W. Rozycki" <macro@orcam.me.uk>
Subject: Re: [PATCH 2/2] GDB: Use gdb::array_view for buffers used in register reading and unwinding
Date: Sat, 11 Jan 2025 21:32:49 -0300 [thread overview]
Message-ID: <871px898i6.fsf@linaro.org> (raw)
In-Reply-To: <28934663-54a6-47cf-8d30-dace9cde8d20@suse.de> (Tom de Vries's message of "Sat, 11 Jan 2025 17:01:37 +0100")
Tom de Vries <tdevries@suse.de> writes:
> On 1/11/25 16:46, Thiago Jung Bauermann wrote:
>> Hello Tom,
>> Tom de Vries <tdevries@suse.de> writes:
>>
>>> On 1/10/25 23:28, Thiago Jung Bauermann wrote:
>> Thank you for debugging the issue! So memcpy was overflowing the
>> buffer. Nice to see the assert in action. :)
>
> Hi Thiago,
>
> thanks for the quick review.
Too quick, as it turns out. Looking at it again, that fix relies on
buffer.size () reflecting the correct size of the register being
unwound. Simon found a counterexample in i386_unwind_pc, which is used
for both i386 and x86_64 and thus passes an 8-byte buffer:
https://inbox.sourceware.org/gdb-patches/321e71e0-43de-4604-bb7e-34f6f64b83bf@simark.ca/
> Not the memcpy, but the memset, because the optimized out branch was activated, but buffer
> overflow indeed.
>
>>> Properly fixing this requires us to only look at the part that is relevant, copying the
>>> value from there, and checking for optimized out and unavailable only there.
>>>
>>> This worked for s390x-linux:
>>> ...
>>> diff --git a/gdb/frame.c b/gdb/frame.c
>>> index 10a32dcd896..02583857019 100644
>>> --- a/gdb/frame.c
>>> +++ b/gdb/frame.c
>>> @@ -1193,8 +1193,14 @@ frame_register_unwind (const frame_info_ptr &next_frame, int
>>> regnum,
>>>
>>> gdb_assert (value != NULL);
>>>
>>> - *optimizedp = value->optimized_out ();
>>> - *unavailablep = !value->entirely_available ();
>>> + if (value->lazy ())
>>> + value->fetch_lazy ();
>>> +
>>> + *optimizedp
>>> + = value->bits_any_optimized_out (value->offset () * 8,
>>> + buffer.size () * 8);
>>> + *unavailablep
>>> + = !value->bytes_available (value->offset (), buffer.size ());
>>> *lvalp = value->lval ();
>>> *addrp = value->address ();
>>> if (*lvalp == lval_register)
>>> @@ -1204,13 +1210,17 @@ frame_register_unwind (const frame_info_ptr &next_frame, int
>>> regnum,
>>>
>>> if (!buffer.empty ())
>>> {
>>> - gdb_assert (buffer.size () >= value->type ()->length ());
>>> + gdb_assert (buffer.size ()
>>> + <= value->type ()->length () - value->offset ());
>> It should be '>=' above.
>>
>
> That doesn't work unfortunately:
> - buffer.size () is 8
> - value->type ()->length () is 16
> - value->offset () == 0
>
> So we'd have gdb_assert (8 >= 16).
Ah, I didn't know offset was 0. We do need an assert that the buffer is
big enough though. :/
> FWIW, I've tried out a less intrusive fix which also works:
> ...
> diff --git a/gdb/frame.c b/gdb/frame.c
> index 10a32dcd896..96e0752888f 100644
> --- a/gdb/frame.c
> +++ b/gdb/frame.c
> @@ -1191,6 +1191,19 @@ frame_register_unwind (const frame_info_ptr &next_frame, int
> regnum,
>
> value = frame_unwind_register_value (next_frame, regnum);
Your fix below is interesting, but I'm starting to think that the real
bug is that frame_unwind_register_value returns a value with a type that
isn't regnum's type. Even if the value was found in another register,
that shouldn't concern the caller. WDYT?
Also, should I revert the patch while we don't find a solution?
> + frame_info_ptr this_frame = get_prev_frame (next_frame);
> + struct gdbarch *gdbarch = frame_unwind_arch (this_frame);
Shouldn't this be either:
struct gdbarch *gdbarch = frame_unwind_arch (next_frame);
or:
struct gdbarch *gdbarch = get_frame_arch (this_frame);
? I still get confused about this/next in frame unwinding...
> + size_t reg_size = register_size (gdbarch, regnum);
> +
> + if (value->type ()->length () > reg_size)
> + {
> + struct value *part_val
> + = value::allocate_register (this_frame, regnum);
Shouldn't next_frame be used here? (Same confused face as above.)
> + value->contents_copy (part_val, 0, value->offset (), reg_size);
> + release_value (value);
> + value = part_val;
> + }
> +
> gdb_assert (value != NULL);
>
> *optimizedp = value->optimized_out ();
> ...
> but I have doubts whether reg_size is correct in case gdbarch changes between frames and
> register sizes are different.
AFAIU GDB should know the gdbarch of each frame in the stack, otherwise
things can get weird. Also, is there another option? As I mentioned
before, the buffer size can't be used unless we audit callers to make
sure they pass a buffer with the same size as the register being unwound
(as Simon mentioned in the email I linked above).
--
Thiago
next prev parent reply other threads:[~2025-01-12 0:33 UTC|newest]
Thread overview: 12+ messages / expand[flat|nested] mbox.gz Atom feed top
2025-01-10 16:43 [PATCH 0/2] Improvements to a few GDB frame unwind functions Thiago Jung Bauermann
2025-01-10 16:43 ` [PATCH 1/2] GDB: frame: Make VALUEP argument optional in frame_register_unwind Thiago Jung Bauermann
2025-01-10 17:02 ` Simon Marchi
2025-01-10 22:23 ` Thiago Jung Bauermann
2025-01-10 16:44 ` [PATCH 2/2] GDB: Use gdb::array_view for buffers used in register reading and unwinding Thiago Jung Bauermann
2025-01-10 17:45 ` Simon Marchi
2025-01-10 22:28 ` Thiago Jung Bauermann
2025-01-11 13:54 ` Tom de Vries
2025-01-11 15:46 ` Thiago Jung Bauermann
2025-01-11 16:01 ` Tom de Vries
2025-01-12 0:32 ` Thiago Jung Bauermann [this message]
2025-01-13 16:40 ` Tom de Vries
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=871px898i6.fsf@linaro.org \
--to=thiago.bauermann@linaro.org \
--cc=gdb-patches@sourceware.org \
--cc=macro@orcam.me.uk \
--cc=simark@simark.ca \
--cc=tankut.baris.aktemur@intel.com \
--cc=tdevries@suse.de \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox