[PING] [PATCH v2] PR gdb/28480: Improve ambiguous member detection
Bruno Larsen
blarsen@redhat.com
Mon Nov 22 13:47:59 GMT 2021
Ping
On 11/8/21 15:27, Bruno Larsen 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 | 19 +++++++++++++++++++
> gdb/testsuite/gdb.cp/ambiguous.exp | 10 ++++++++++
> gdb/valops.c | 27 +++++++++++++++++++++++++++
> 3 files changed, 56 insertions(+)
>
> diff --git a/gdb/testsuite/gdb.cp/ambiguous.cc b/gdb/testsuite/gdb.cp/ambiguous.cc
> index a55686547f2..af2198dcfbc 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,17 @@ public:
> int y;
> };
>
> +#if !defined (__GNUC__) || __GNUC__ > 7
> +# define NO_UNIQUE_ADDRESS [[no_unique_address]]
> +#else
> +# define NO_UNIQUE_ADDRESS
> +#endif
> +
> +class A4 {
> +public:
> + NO_UNIQUE_ADDRESS empty x;
> +};
> +
> class X : public A1, public A2 {
> public:
> int z;
> @@ -77,6 +89,10 @@ public:
> int jva1v;
> };
>
> +class JE : public A1, public A4 {
> +public:
> +};
> +
> int main()
> {
> A1 a1;
> @@ -92,6 +108,7 @@ int main()
> JVA1 jva1;
> JVA2 jva2;
> JVA1V jva1v;
> + JE je;
>
> int i;
>
> @@ -173,5 +190,7 @@ int main()
> jva1v.i = 4;
> jva1v.jva1v = 5;
>
> + je.A1::x = 1;
> +
> return 0; /* set breakpoint here */
> }
> diff --git a/gdb/testsuite/gdb.cp/ambiguous.exp b/gdb/testsuite/gdb.cp/ambiguous.exp
> index 008898c5818..a2a7b02b113 100644
> --- a/gdb/testsuite/gdb.cp/ambiguous.exp
> +++ b/gdb/testsuite/gdb.cp/ambiguous.exp
> @@ -264,3 +264,13 @@ 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}"
> +
> +# C++20 introduced a way to have ambiguous fields with the same boffset.
> +# This class explicitly tests for that.
> +# if this is tested with a compiler that can't handle [[no_unique_address]]
> +# the code should still correctly identify the ambiguity because of
> +# different boffsets.
> +test_ambiguous "je.x" "x" "JE" {
> + "'int A1::x' (JE -> A1)"
> + "'empty A4::x' (JE -> A4)"
> +}
> diff --git a/gdb/valops.c b/gdb/valops.c
> index 9787cdbb513..2989a93df1a 100644
> --- a/gdb/valops.c
> +++ b/gdb/valops.c
> @@ -1962,6 +1962,33 @@ 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
> + different. This is not necessarily complete, but a situation where
> + this assumption is incorrect is currently (2021) impossible. */
> + {
> + bool ambiguous = false, insert = true;
> + for (const found_field& field: m_fields) {
> + if(field.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. */
> + insert = false;
> + break;
> + }
> + }
> + if (ambiguous && insert) {
> + m_fields.push_back ({m_struct_path, v});
> + }
> + }
> }
> }
> }
>
--
Cheers!
Bruno Larsen
More information about the Gdb-patches
mailing list