From: Simon Marchi <simark@simark.ca>
To: Simon Marchi <simon.marchi@efficios.com>,
Alan Hayward <Alan.Hayward@arm.com>
Cc: nd <nd@arm.com>,
"gdb-patches\\@sourceware.org" <gdb-patches@sourceware.org>
Subject: Re: [PATCH] gdb/arm: avoid undefined behavior shift when decoding immediate value
Date: Fri, 13 Nov 2020 12:05:05 -0500 [thread overview]
Message-ID: <6d6a7930-9863-0649-5b98-29ea8c09a61d@simark.ca> (raw)
In-Reply-To: <66ee1922-d144-29bc-a8c7-7eceb0b345ce@efficios.com>
On 2020-11-11 3:44 p.m., Simon Marchi via Gdb-patches wrote:
> On 2020-11-11 5:00 a.m., Alan Hayward wrote:
>>
>>
>>> On 9 Nov 2020, at 20:49, Simon Marchi via Gdb-patches <gdb-patches@sourceware.org> wrote:
>>>
>>> From: Simon Marchi <simon.marchi@polymtl.ca>
>>>
>>> When loading the code file provided in PR 26828 and GDB is build with
>>> UBSan, we get:
>>>
>>> Core was generated by `./Foo'.
>>> Program terminated with signal SIGABRT, Aborted.
>>> #0 0xb6c3809c in pthread_cond_wait () from /home/simark/build/binutils-gdb/gdb/repo/lib/libpthread.so.0
>>> [Current thread is 1 (LWP 29367)]
>>> (gdb) bt
>>> /home/simark/src/binutils-gdb/gdb/arm-tdep.c:1551:30: runtime error: shift exponent 32 is too large for 32-bit type 'unsigned int'
>>>
>>
>> This error is because the code is technically wrong - but in reality
>> compilers will plant what we really wanted?
>
> Well, we don't really know, different things can happen on different
> systems. I did this program for fun:
>
> #include <stdlib.h>
> #include <stdio.h>
>
> int main(int argc, char **argv) {
> unsigned int foo = 0xabababab;
> unsigned int shift = atoi(argv[1]);
> printf("Shifting by %d\n", shift);
> foo = foo >> shift;
> printf("%x\n", foo);
> return 0;
> }
>
> Running `./a.out 32`, I get this on AMD64:
>
> Shifting by 32
> abababab
>
> And I get this on PowerPC and ARM:
>
> Shifting by 32
> 0
>
>>> The sequence of instructions at pthread_cond_wait, in the
>>> libpthread.so.0 library, contains this instruction with an immediate
>>> constant with a "rotate amount" of 0:
>>>
>>> e24dd044 sub sp, sp, #68 ; 0x44
>>>
>>> Since it shifts by "32 - rotate amount", arm_analyze_prologue does a 32
>>> bit shift of a 32 bit type, which is caught by UBSan.
>>>
>>
>> Minor nit - it took me a while to figure out that the “it” in “Since it”
>> is the following arm_analyze_prologue and not something in the previous
>> sentence.
>
> Good point, I swapped "it" and "arm_analyze_prologue" to make sure
> "arm_analyze_prologue" comes before.
>
>>
>>> Fix it by factoring out the decoding of immediates in a new function,
>>> arm_expand_immediate.
>>>
>>> I added a selftest for arm_analyze_prologue that replicates the
>>> instruction sequence. Without the fix, it crashes GDB if it is build
>>> with --enable-ubsan.
>>>
>>> I initially wanted to re-use the abstract_memory_reader class already in
>>> arm-tdep.c, used to make arm_process_record testable. However,
>>> arm_process_record and arm_analyze_prologue don't use the same kind of
>>> memory reading functions. arm_process_record uses a function that
>>> returns an error status on failure while arm_analyze_prologue uses one
>>> that throws an exception. Since i didn't want to introduce any other
>>> behavior change, I decided to just introduce a separate interface
>>> (arm_instruction_reader). It is derived from
>>> abstract_instruction_reader in aarch64-tdep.c.
>>
>> I both don’t like this and can’t see a better way of doing it :)
>> So, I’m ok with it
>
> Same. I really wanted not to add another class, but I also didn't want
> this simple fix to become a huge refactor.
>
>>> @@ -1485,6 +1511,26 @@ arm_instruction_restores_sp (unsigned int insn)
>>> return 0;
>>> }
>>>
>>> +/* Implement immediate value decoding, as described in section A5.2.4
>>> + (Modified immediate constants in ARM instructions) of the ARM Architecture
>>> + Reference Manual. */
>>
>>
>> "of the ARM Architecture Reference Manual (ARMv7-A and ARMv7-R edition)"
>>
>> Just to make sure no one is looking for that section in the v8 doc.
>
> Done.
>
>>> @@ -9618,6 +9658,7 @@ vfp - VFP co-processor."),
>>>
>>> #if GDB_SELF_TEST
>>> selftests::register_test ("arm-record", selftests::arm_record_test);
>>> + selftests::register_test ("arm_analyze_prologue", selftests::arm_analyze_prologue_test);
>>> #endif
>>
>> Given the size of the tdep files, I wonder if it’s worth putting the tests into separate
>> files, eg arm-tdep-selftests.c
>> (Probably not for this patch though)
>
> Possibly. That requires exposing (making non-static) functions that are not usually exposed
> though.
>
>>> }
>>> @@ -13254,6 +13295,63 @@ arm_record_test (void)
>>> SELF_CHECK (arm_record.arm_regs[0] == 7);
>>> }
>>> }
>>> +
>>> +/* Instruction reader from manually cooked instruction sequences. */
>>> +
>>> +class test_arm_instruction_reader : public arm_instruction_reader
>>> +{
>>> +public:
>>> + template<size_t SIZE>
>>> + explicit test_arm_instruction_reader (const uint32_t (&insns)[SIZE])
>>> + : m_insns (insns), m_insns_size (SIZE)
>>
>> Why the need for a template?
>> Is it just so that m_insns_size can be determined automatically?
>
> I don't really know, I just copied the AArch64 one :). But yeah I think
> that's it. It could also use a gdb::array_view, that would be simpler I
> think. I would change it for:
>
> /* Instruction reader from manually cooked instruction sequences. */
>
> class test_arm_instruction_reader : public arm_instruction_reader
> {
> public:
> explicit test_arm_instruction_reader (gdb::array_view<const uint32_t> insns)
> : m_insns (insns)
> {}
>
> uint32_t read (CORE_ADDR memaddr, enum bfd_endian byte_order) const override
> {
> SELF_CHECK (memaddr % 4 == 0);
> SELF_CHECK (memaddr / 4 < m_insns.size ());
>
> return m_insns[memaddr / 4];
> }
>
> private:
> const gdb::array_view<const uint32_t> m_insns;
> };
>
> Simon
>
I pushed the patch with the changes mentioned above.
Simon
next prev parent reply other threads:[~2020-11-13 17:05 UTC|newest]
Thread overview: 6+ messages / expand[flat|nested] mbox.gz Atom feed top
2020-11-09 20:49 Simon Marchi via Gdb-patches
2020-11-11 10:00 ` Alan Hayward via Gdb-patches
2020-11-11 20:44 ` Simon Marchi via Gdb-patches
2020-11-13 17:05 ` Simon Marchi [this message]
2020-11-13 22:35 ` Luis Machado via Gdb-patches
2020-11-14 16:20 ` Simon Marchi
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=6d6a7930-9863-0649-5b98-29ea8c09a61d@simark.ca \
--to=simark@simark.ca \
--cc=Alan.Hayward@arm.com \
--cc=gdb-patches@sourceware.org \
--cc=nd@arm.com \
--cc=simon.marchi@efficios.com \
/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