public inbox for gdb-patches@sourceware.org
 help / color / mirror / Atom feed
From: Simon Marchi <simark@simark.ca>
To: Bruno Larsen <blarsen@redhat.com>, gdb-patches@sourceware.org
Subject: Re: [PATCH] PR gdb/28480: Improve ambiguous member detection
Date: Fri, 5 Nov 2021 13:54:13 -0400	[thread overview]
Message-ID: <0e7f3dbb-ef25-9d60-42da-b01c57eb8efa@simark.ca> (raw)
In-Reply-To: <20211104210457.35512-1-blarsen@redhat.com>

On 2021-11-04 5:04 p.m., Bruno Larsen via Gdb-patches wrote:
> Basic ambiguity detection assumes that when 2 fields with the same name
> have the same boffset, it must be an unambiguous request. This is not
> always correct. Consider the following code:
>
> class empty { };
>
> class A {
> public:
>   [[no_unique_address]] empty e;
> };
>
> class B {
> public:
>   int e;
> };
>
> class C: public A, public B { };
>
> if we tried to use c.e in code, the compiler would warn of an ambiguity,
> however, since A::e does not demand an unique address, it gets the same
> address (and thus boffset) of the members, making A::e and B::e have the
> same address. however, "print c.e" would fail to report the ambiguity,
> and would instead print it as an empty class (first path found).
>
> The new code solves this by checking for other found_fields that have
> different m_struct_path.back() (final class that the member was found
> in), despite having the same boffset.
>
> The testcase gdb.cp/ambiguous.exp was also changed to test for this
> behavior.
> ---
>  gdb/testsuite/gdb.cp/ambiguous.cc  | 13 +++++++++++++
>  gdb/testsuite/gdb.cp/ambiguous.exp |  7 +++++++
>  gdb/valops.c                       | 26 ++++++++++++++++++++++++++
>  3 files changed, 46 insertions(+)
>
> diff --git a/gdb/testsuite/gdb.cp/ambiguous.cc b/gdb/testsuite/gdb.cp/ambiguous.cc
> index a55686547f2..b2be7297b28 100644
> --- a/gdb/testsuite/gdb.cp/ambiguous.cc
> +++ b/gdb/testsuite/gdb.cp/ambiguous.cc
> @@ -1,3 +1,4 @@
> +class empty { };
>
>  class A1 {
>  public:
> @@ -17,6 +18,11 @@ public:
>    int y;
>  };
>
> +class A4 {
> +public:
> +    [[no_unique_address]] empty x;

In theory, no_unique_address appeared in C++20.  Having
[[no_unique_address]] in the source code means that compiling this file
with an older compiler that doesn't know about it, or in a standard mode
where it isn't recognized, will lead to the entire test being skipped.
In practice, it looks like older-but-not-too-old g++s cope well with it.
For example, g++ 7 prints a warning:

    $ g++-7 ambiguous.cc
    ambiguous.cc:23:33: warning: ‘no_unique_address’ attribute directive ignored [-Wattributes]
         [[no_unique_address]] empty x;
                                     ^

... but since we disable all warnings in that tests for g++ < 10, then
it still compiles.  The no_unique_address attribute has no effect,  but
that's fine.

With older g++s, like 4.8, it fails though:

    $ make check TESTS="gdb.cp/ambiguous.exp" RUNTESTFLAGS='CC_FOR_TARGET=gcc-4.8 CXX_FOR_TARGET=g++-4.8'
    ...
    Running /home/smarchi/src/binutils-gdb/gdb/testsuite/gdb.cp/ambiguous.exp ...
    Gdb compile failed, /home/smarchi/src/binutils-gdb/gdb/testsuite/gdb.cp/ambiguous.cc:23:5: error: expected unqualified-id before '[' token
         [[no_unique_address]] empty x;
         ^

I don't know if others care about this test running with older
compilers, but if so we could make that case optional with some
preprocessor conditionals.

> diff --git a/gdb/testsuite/gdb.cp/ambiguous.exp b/gdb/testsuite/gdb.cp/ambiguous.exp
> index 008898c5818..68b82d45b68 100644
> --- a/gdb/testsuite/gdb.cp/ambiguous.exp
> +++ b/gdb/testsuite/gdb.cp/ambiguous.exp
> @@ -264,3 +264,10 @@ gdb_test "print (A1)(KV)jva1" " = \{x = 3, y = 4\}"
>  # JVA1V is derived from A1; A1 is a virtual base indirectly
>  # and also directly; must not report ambiguity when a JVA1V is cast to an A1.
>  gdb_test "print (A1)jva1v" " = {x = 1, y = 2}"
> +
> +#unique_ptr is a weird edge-case that interacts differently with the
> +#ambiguity detection, so we should test it directly
> +test_ambiguous "je.x" "x" "JE" {
> +    "'int A1::x' (JE -> A1)"
> +    "'empty A4::x' (JE -> A4)"
> +}

I think the comment needs to be re-worded to not talk about unique_ptr,
but talk about ambiguous fields that have the same address due to
no_unique_address.  Make sure to use a space at the beginning of the
line and a period at the end (like the other comments).

> diff --git a/gdb/valops.c b/gdb/valops.c
> index 9787cdbb513..75b732af62b 100644
> --- a/gdb/valops.c
> +++ b/gdb/valops.c
> @@ -1962,6 +1962,32 @@ struct_field_searcher::update_result (struct value *v, LONGEST boffset)
>  	     space.  */
>  	  if (m_fields.empty () || m_last_boffset != boffset)
>  	    m_fields.push_back ({m_struct_path, v});
> +	  else
> +	  /* Some fields may occupy the same space and still be ambiguous.
> +	     This happens when [[no_unique_address]] is used by a member
> +	     of the class. We assume that this only happens when the types are

Two spaces after period.

> +	     different. This is not necessarily complete, but a situation where
> +	     this assumption is incorrect is unlikely*/

Period and two spaces:

 ... unlikely.  */

> +	  {
> +	      bool ambiguous = false, insert = true;
> +	      for(auto finds: m_fields){

Space before opening parentheses and after closing.

Iterate using const-reference, to avoid copying the items as we are
iterating.  I would also use the type name instead of auto, for clarity,
but I am ok with either.  Lastly, the variable name "finds" is a bit
strange, or I don't understand what you mean by it.

> +		  if(finds.path.back() != m_struct_path.back())
> +		  {
> +		      /* Same boffset points to members of different classes.
> +		         We have found an ambiguity and should record it*/
> +		      ambiguous = true;
> +		  }
> +		  else
> +		  {
> +		      /* we don't need to insert this value again, because a
> +		         non-ambiguous path already leads to it */

First letter capital, period + two spaces at the end.

There are two lines above that have more than 8 spaces, that should be
replaced with a tab.  Most editors have a way to configure whitespaces
to do that automatically.

> +		      insert = false;

Since this path makes it so that we'll definitely not insert, we can
break the iteration.

Simon

  reply	other threads:[~2021-11-05 17:54 UTC|newest]

Thread overview: 3+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2021-11-04 21:04 Bruno Larsen
2021-11-05 17:54 ` Simon Marchi [this message]
2021-11-05 18:26   ` Bruno Larsen

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=0e7f3dbb-ef25-9d60-42da-b01c57eb8efa@simark.ca \
    --to=simark@simark.ca \
    --cc=blarsen@redhat.com \
    --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).