public inbox for gdb-patches@sourceware.org
 help / color / mirror / Atom feed
From: Tom de Vries <tdevries@suse.de>
To: Bernd Edlinger <bernd.edlinger@hotmail.de>,
	"gdb-patches@sourceware.org" <gdb-patches@sourceware.org>
Subject: Re: [PATCH v3 1/2] [gdb/symtab] Fix an out of bounds array access in find_epilogue_using_linetable
Date: Tue, 9 Apr 2024 11:37:12 +0200	[thread overview]
Message-ID: <74723da4-ce6e-4eae-a764-c47e80f9f7bc@suse.de> (raw)
In-Reply-To: <AS8P193MB1285EBEE93C204041C55F8AAE4002@AS8P193MB1285.EURP193.PROD.OUTLOOK.COM>

On 4/8/24 16:41, Bernd Edlinger wrote:
> Hi Tom,
> 
> we are making good progress.
> 

Agreed :)

> On 4/8/24 14:58, Tom de Vries wrote:
>> On 4/7/24 10:17, Bernd Edlinger wrote:
>>>
>>> Hmm, this can be an assertion, because
>>> the line table was found by find_pc_line (start_pc, 0);
>>> so the linetable is guaranteed to be non-empty.
>>> BTW: empty linetables are usually NULL pointers,
>>> so that probably the assertion should
>>> also assert like
>>> gdb_assert (linetable != NULL && linetable->nitems > 0);
>>>
>>
>> I've updated the if condition to include the nullptr check, but didn't turn it into an assert.  By doing so we gain nothing, and add a potential user inconvenience.
>>
> 
> ok.
> 
>>>>
>>>> We could also just simply handle the cornercase by returning {}, I went forth and back a bit on that, and decided to support it on the basis that at least currently we have dwarf assembly test-cases in the testsuite that trigger this path, though I've submitted a series to clean that up.
>>>>
>>>> But I'm still on the fence about this, if you prefer a "return {}" I'm fine with that.
>>>>
>>
>> I've thought about this a bit more over the weekend, and I managed to convince myself that a simple "return {}" is the proper solution.  The rationale is that an incorrectly written dwarf assembly test-case is not a good reason to support a corner-case.  If we do stumble one day into a compiler that generates the incorrect debug info, we can always opt to add a workaround for this (which we then can test extensively).  But adding a workaround without such an incentive is pointless.
>>
>>>>>> +    }
>>>>>> +      else
>>>>>> +    gdb_assert (unrel_end <= it->unrelocated_pc ());
>>>>>
>>>>> Why do you not check that 'it' points to an end_sequence
>>>>> at exactly unrel_end?
>>>>> It could be anything at an address much higher PC than unrel_end.
>>>>
>>>> This assert spells out the post-condition of the call to std::lower_bound, in case it found an entry.
>>>>
>>>> If there's debug info where one line entry straddles two functions, the call returns the entry after it, which doesn't have address unrel_end.
>>>>
>>>> Having said that, we can unsupport such a scenario by doing:
>>>> ...
>>>>         else
>>>>           {
>>>>             if (unrel_end < it->unrelocated_pc ())
>>>>               return {};
>>>>             gdb_assert (unrel_end == it->unrelocated_pc ());
>>>> ...
>>>>
>>>
>>> I think we should not look at the `it` in any case.
>>> If there is an inconsistency in the debug info, a
>>> debug message that can be enabled in maintainer mode
>>> would be good enough.
>>> But even in this case, I would prefer a best effort,
>>> and continue whenever possible.
>>>
>>
>> IMO, a best effort only makes sense in case there's a compiler release generating the incorrect debug info.
>>
> 
> Consider this counter example:
> The debug info is correct, but the internal representation
> is not what you probably expect.
> 
> $ cat hello.c
> #include <stdio.h>
> int main()
> {
>    printf("hello ");
>    #include "world.inc"
> /*** End of hello.c ***/
> 
> $ cat world.inc
>    printf("world\n");
>    return 0;
> }
> /*** End of world.inc ***/
> 
> gcc -g -o hello hello.c
> 
> The line table starting at main ends between
> the two printf statements.
> 
> I demonstrate the effect this little mod over
> your v4 patch version:
> 
> diff --git a/gdb/amd64-tdep.c b/gdb/amd64-tdep.c
> index 0bb7a24cbd0..35c1fb85409 100644
> --- a/gdb/amd64-tdep.c
> +++ b/gdb/amd64-tdep.c
> @@ -2908,6 +2908,7 @@ amd64_epilogue_frame_sniffer_1 (const struct frame_unwind *self,
>       /* We're not in the inner frame, so assume we're not in an epilogue.  */
>       return 0;
>   
> +#if 0
>     bool unwind_valid_p
>       = compunit_epilogue_unwind_valid (find_pc_compunit_symtab (pc));
>     if (override_p)
> @@ -2924,6 +2925,7 @@ amd64_epilogue_frame_sniffer_1 (const struct frame_unwind *self,
>             "amd64 epilogue".  */
>          return 0;
>       }
> +#endif
>   
>     /* Check whether we're in an epilogue.  */
>     return amd64_stack_frame_destroyed_p_1 (gdbarch, pc);
> diff --git a/gdb/symtab.c b/gdb/symtab.c
> index 427d7b9f8b2..bb3c1bba70b 100644
> --- a/gdb/symtab.c
> +++ b/gdb/symtab.c
> @@ -4192,6 +4192,7 @@ find_epilogue_using_linetable (CORE_ADDR func_addr)
>               extent of the function, which shouldn't happen with
>               compiler-generated debug info.  Handle the corner case
>               conservatively.  */
> +         printf("at linetable end nitems=%d\n", linetable->nitems);
>            return {};
>          }
>         else
> @@ -4202,6 +4203,7 @@ find_epilogue_using_linetable (CORE_ADDR func_addr)
>                   function.  This can happen if the previous entry straddles
>                   two functions, which shouldn't happen with compiler-generated
>                   debug info.  Handle the corner case conservatively.  */
> +             printf("unrel_end = %lx < it->unrelocated_pc = %lx\n", (long)unrel_end, (long)it->unrelocated_pc());
>                return {};
>              }
>            gdb_assert (unrel_end == it->unrelocated_pc ());
> 

Nice.  I've filed this as a PR ( 
https://sourceware.org/bugzilla/show_bug.cgi?id=31622 ) since it's an 
orthogonal issue, and added your suggested fix with a test-case in a 
separate patch in v5.

> So this debug info which is not invalid at all,
> triggers your error conditions:
> 

IIUC, one of them.

Anyway, I've updated the comments to reflect this situation, and also 
added a comment that was part of the commit message of the initial 
commit adding find_epilogue_using_linetable.

V5 submitted here ( 
https://sourceware.org/pipermail/gdb-patches/2024-April/207959.html ).

Thanks,
- Tom

> $ ..../gdb-build/gdb/gdb hello
> GNU gdb (GDB) 15.0.50.20240406-git
> Copyright (C) 2024 Free Software Foundation, Inc.
> License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
> This is free software: you are free to change and redistribute it.
> There is NO WARRANTY, to the extent permitted by law.
> Type "show copying" and "show warranty" for details.
> This GDB was configured as "x86_64-pc-linux-gnu".
> Type "show configuration" for configuration details.
> For bug reporting instructions, please see:
> <https://www.gnu.org/software/gdb/bugs/>.
> Find the GDB manual and other documentation resources online at:
>      <http://www.gnu.org/software/gdb/documentation/>.
> 
> For help, type "help".
> Type "apropos word" to search for commands related to "word"...
> Reading symbols from hello...
> (gdb) b main
> Breakpoint 1 at 0x114d: file hello.c, line 4.
> (gdb) r
> Starting program: /home/.../hello
> [Thread debugging using libthread_db enabled]
> Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1".
> at linetable end nitems=3
> 
> Breakpoint 1, main () at hello.c:4
> 4	  printf("hello ");
> (gdb) n
> at linetable end nitems=3
> at linetable end nitems=3
> 1	  printf("world\n");
> (gdb) n
> hello world
> at linetable end nitems=3
> at linetable end nitems=3
> 2	  return 0;
> (gdb) maint info line-table
> objfile: .../hello ((struct objfile *) 0x5641508bf6b0)
> compunit_symtab: hello.c ((struct compunit_symtab *) 0x5641508bfbc0)
> symtab: .../hello.c ((struct symtab *) 0x5641508bfc40)
> linetable: ((struct linetable *) 0x564150920ce0):
> INDEX  LINE   REL-ADDRESS        UNREL-ADDRESS      IS-STMT PROLOGUE-END EPILOGUE-BEGIN
> 0      3      0x0000555555555149 0x0000000000001149 Y
> 1      4      0x000055555555514d 0x000000000000114d Y
> 2      END    0x0000555555555161 0x0000000000001161 Y
> 
> objfile: .../hello ((struct objfile *) 0x5641508bf6b0)
> compunit_symtab: hello.c ((struct compunit_symtab *) 0x5641508bfbc0)
> symtab: .../world.inc ((struct symtab *) 0x5641508bfc80)
> linetable: ((struct linetable *) 0x564150920c80):
> INDEX  LINE   REL-ADDRESS        UNREL-ADDRESS      IS-STMT PROLOGUE-END EPILOGUE-BEGIN
> 0      1      0x0000555555555161 0x0000000000001161 Y
> 1      2      0x0000555555555170 0x0000000000001170 Y
> 2      3      0x0000555555555175 0x0000000000001175 Y
> 3      END    0x0000555555555177 0x0000000000001177 Y
> 
> objfile: .../hello ((struct objfile *) 0x5641508bf6b0)
> compunit_symtab: hello.c ((struct compunit_symtab *) 0x5641508bfbc0)
> symtab: /usr/include/stdio.h ((struct symtab *) 0x5641508bfcc0)
> linetable: ((struct linetable *) 0x0):
> No line table.
> 
> 
> And this is also why I would suggest to look into using
> the line-table that has addresses near the end of the range
> like this:
> 
> --- a/gdb/symtab.c
> +++ b/gdb/symtab.c
> @@ -4156,7 +4156,7 @@ find_epilogue_using_linetable (CORE_ADDR func_addr)
>     if (!find_pc_partial_function (func_addr, nullptr, &start_pc, &end_pc))
>       return {};
>   
> -  const struct symtab_and_line sal = find_pc_line (start_pc, 0);
> +  const struct symtab_and_line sal = find_pc_line (end_pc - 1, 0);
>     if (sal.symtab != nullptr && sal.symtab->language () != language_asm)
>       {
>         struct objfile *objfile = sal.symtab->compunit ()->objfile ();
> 
> 
> 
> Thanks
> Bernd.


      reply	other threads:[~2024-04-09  9:36 UTC|newest]

Thread overview: 8+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2024-04-05 15:10 Tom de Vries
2024-04-05 15:10 ` [PATCH v3 2/2] [gdb/testsuite] Add gdb.dwarf2/dw2-epilogue-begin-2.exp Tom de Vries
2024-04-06  5:03 ` [PATCH v3 1/2] [gdb/symtab] Fix an out of bounds array access in find_epilogue_using_linetable Bernd Edlinger
2024-04-06  8:29   ` Tom de Vries
2024-04-07  8:17     ` Bernd Edlinger
2024-04-08 12:58       ` Tom de Vries
2024-04-08 14:41         ` Bernd Edlinger
2024-04-09  9:37           ` Tom de Vries [this message]

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=74723da4-ce6e-4eae-a764-c47e80f9f7bc@suse.de \
    --to=tdevries@suse.de \
    --cc=bernd.edlinger@hotmail.de \
    --cc=gdb-patches@sourceware.org \
    /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;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).