[applied] Bug 29686 - Fix testing the presence of anonymous data member in a struct

Message ID 87fs9qmt3q.fsf@redhat.com
State New
Headers
Series [applied] Bug 29686 - Fix testing the presence of anonymous data member in a struct |

Commit Message

Dodji Seketeli March 27, 2023, 9:38 a.m. UTC
  Hello,

When in "updating mode", add_or_update_class_type fails (in some cases)
to detect that an anonymous data member has already been added to the
class and thus, the class ends up having that data member added twice,
leading to issues later down the road.

In the particular example filed in this bug,
class_or_union::find_data_member is using the flat representation of the
type of the data member to try to identify it inside the class.  This
doesn't work, for instance, if the anonymous data member's type contain
a recursive type that is currently being built.

To fix that, a new function anonymous_data_member_exists_in_class is
introduced.  It looks up for every single named sub-member of the
anonymous data member inside the class, to see if the anonymous data
member exists in the class.  That is close to how anonymous data members
are meant to work, as far as member lookup is concerned.

	* include/abg-fwd.h (anonymous_data_member_to_class_or_union): Add
	a new overload.
	(anonymous_data_member_exists_in_class): Declare new function.
	* src/abg-dwarf-reader.cc (add_or_update_class_type): Use the new
	anonymous_data_member_exists_in_class function.
	* src/abg-ir.cc (anonymous_data_member_to_class_or_union): Define
	new function.
	* tests/data/test-read-dwarf/test-libandroid.so.abi: Adjust.

Signed-off-by: Dodji Seketeli <dodji@redhat.com>
---
 include/abg-fwd.h                             |  7 +++
 src/abg-dwarf-reader.cc                       |  3 +-
 src/abg-ir.cc                                 | 56 +++++++++++++++++++
 .../test-read-dwarf/test-libandroid.so.abi    |  3 -
 4 files changed, 65 insertions(+), 4 deletions(-)
  

Patch

diff --git a/include/abg-fwd.h b/include/abg-fwd.h
index 747a625c..25e67395 100644
--- a/include/abg-fwd.h
+++ b/include/abg-fwd.h
@@ -727,6 +727,13 @@  anonymous_data_member_to_class_or_union(const var_decl*);
 class_or_union_sptr
 anonymous_data_member_to_class_or_union(const var_decl_sptr&);
 
+class_or_union_sptr
+anonymous_data_member_to_class_or_union(const var_decl&);
+
+bool
+anonymous_data_member_exists_in_class(const var_decl& anon_dm,
+				      const class_or_union& clazz);
+
 bool
 scope_anonymous_or_typedef_named(const decl_base&);
 
diff --git a/src/abg-dwarf-reader.cc b/src/abg-dwarf-reader.cc
index 37367dba..5ca1cee7 100644
--- a/src/abg-dwarf-reader.cc
+++ b/src/abg-dwarf-reader.cc
@@ -13138,7 +13138,8 @@  add_or_update_class_type(reader&	 rdr,
 	      die_access_specifier(&child, access);
 
 	      var_decl_sptr dm(new var_decl(n, t, loc, m));
-	      if (n.empty() && result->find_data_member(dm))
+	      if (n.empty()
+		  && anonymous_data_member_exists_in_class(*dm, *result))
 		// dm is an anonymous data member that was already
 		// present in the current class so let's not add it.
 		continue;
diff --git a/src/abg-ir.cc b/src/abg-ir.cc
index 514013c7..a5b8e90a 100644
--- a/src/abg-ir.cc
+++ b/src/abg-ir.cc
@@ -5951,6 +5951,20 @@  anonymous_data_member_to_class_or_union(const var_decl* d)
   return 0;
 }
 
+/// Get the @ref class_or_union type of a given anonymous data member.
+///
+/// @param d the anonymous data member to consider.
+///
+/// @return the @ref class_or_union type of the anonymous data member
+/// @p d.
+class_or_union_sptr
+anonymous_data_member_to_class_or_union(const var_decl& d)
+{
+  if (is_anonymous_data_member(d))
+    return is_class_or_union_type(d.get_type());
+  return class_or_union_sptr();
+}
+
 /// Test if a data member has annonymous type or not.
 ///
 /// @param d the data member to consider.
@@ -6006,6 +6020,48 @@  anonymous_data_member_to_class_or_union(const var_decl_sptr &d)
   return class_or_union_sptr();
 }
 
+/// Test if a given anonymous data member exists in a class or union.
+///
+/// @param anon_dm the anonymous data member to consider.
+///
+/// @param clazz the class to consider.
+///
+/// @return true iff @p anon_dm exists in the @clazz.
+bool
+anonymous_data_member_exists_in_class(const var_decl& anon_dm,
+				      const class_or_union& clazz)
+{
+  if (!anon_dm.get_is_anonymous()
+      || !is_class_or_union_type(anon_dm.get_type()))
+    return false;
+
+  class_or_union_sptr cl = is_class_or_union_type(anon_dm.get_type());
+  ABG_ASSERT(cl);
+
+  // Look for the presence of each data member of anon_dm in clazz.
+  //
+  // If one data member of anon_dm is not present in clazz, then the
+  // data member anon_dm is considered to not exist in clazz.
+  for (auto anon_dm_m : cl->get_non_static_data_members())
+    {
+      // If the data member anon_dm_m is not an anonymous data member,
+      // it's easy to look for it.
+      if (!is_anonymous_data_member(anon_dm_m))
+	{
+	  if (!clazz.find_data_member(anon_dm_m->get_name()))
+	    return false;
+	}
+      // If anon_dm_m is itself an anonymous data member then recurse
+      else
+	{
+	  if (!anonymous_data_member_exists_in_class(*anon_dm_m, clazz))
+	    return false;
+	}
+    }
+
+  return true;
+}
+
 /// Test if the scope of a given decl is anonymous or anonymous with a
 /// naming typedef.
 ///
diff --git a/tests/data/test-read-dwarf/test-libandroid.so.abi b/tests/data/test-read-dwarf/test-libandroid.so.abi
index 8b15c0e9..4ef47d7a 100644
--- a/tests/data/test-read-dwarf/test-libandroid.so.abi
+++ b/tests/data/test-read-dwarf/test-libandroid.so.abi
@@ -11061,9 +11061,6 @@ 
               <data-member access='public' layout-offset-in-bits='16'>
                 <var-decl name='__data_' type-id='72631341' visibility='default' filepath='external/libcxx/include/string' line='761' column='1'/>
               </data-member>
-              <data-member access='public' layout-offset-in-bits='0'>
-                <var-decl name='' type-id='ac5ab59f' visibility='default' filepath='external/libcxx/include/string' line='756' column='1'/>
-              </data-member>
             </class-decl>
           </member-type>
           <member-type access='private'>