Ensure die_function_type_is_method_type returns a class type die
authorDodji Seketeli <dodji@redhat.com>
Fri, 29 Jun 2018 10:32:02 +0000 (12:32 +0200)
committerDodji Seketeli <dodji@redhat.com>
Fri, 29 Jun 2018 11:06:57 +0000 (13:06 +0200)
When die_function_type_is_method returns true, it meanins that the
function die it's looking at is a member function.  In that case,
die_function_type_is_method must also return the class of which the
function is a member.  It appears that there are cases where this
die_function_type_is_method returns a *typedef* DIE (to a class DIE),
rather than a class DIE.

This results in the assertion violation below when loading the file
/usr/lib/libreoffice/program/libanalysislo.so from, e.g, the
libreoffice-calc-5.3.6.1-10.el7.i686 package:

    /home/dodji/git/libabigail/master/src/abg-dwarf-reader.cc:13846: abigail::ir::function_type_sptr abigail::dwarf_reader::build_function_type(abigail::dwarf_reader::read_context&, Dwarf_Die*, abigail::ir::class_or_union_sptr, size_t): Assertion `klass_type' failed.

This patch fixes that by peeling off the potential typedefs that might
be there.

* src/abg-dwarf-reader.cc (die_peel_typedef): Define new static
function.
(die_function_type_is_method_type): Use the function above to peel
the class die from potential typedefs wrapping it.

Signed-off-by: Dodji Seketeli <dodji@redhat.com>
src/abg-dwarf-reader.cc

index c95237c..890ac10 100644 (file)
@@ -8901,6 +8901,41 @@ die_peel_qual_ptr(Dwarf_Die *die, Dwarf_Die& peeled_die)
   return true;
 }
 
+/// Return the leaf object under a typedef type DIE.
+///
+/// @param die the DIE of the type to consider.
+///
+/// @param peeled_die out parameter.  Set to the DIE of the leaf
+/// object iff the function actually peeled anything.
+///
+/// @return true upon successful completion.
+static bool
+die_peel_typedef(Dwarf_Die *die, Dwarf_Die& peeled_die)
+{
+  if (!die)
+    return false;
+
+  int tag = dwarf_tag(die);
+
+  if (tag == DW_TAG_typedef)
+    {
+      if (!die_die_attribute(die, DW_AT_type, peeled_die))
+       return false;
+    }
+  else
+    return false;
+
+  while (tag == DW_TAG_typedef)
+    {
+      if (!die_die_attribute(&peeled_die, DW_AT_type, peeled_die))
+       break;
+      tag = dwarf_tag(&peeled_die);
+    }
+
+  return true;
+
+}
+
 /// Test if a DIE for a function type represents a method type.
 ///
 /// @param ctxt the read context.
@@ -8994,6 +9029,10 @@ die_function_type_is_method_type(const read_context& ctxt,
       // parameter.
       if (!die_peel_qual_ptr(&this_type_die, class_die))
        return false;
+
+      // And make we return a class type, rather than a typedef to a
+      // class.
+      die_peel_typedef(&class_die, class_die);
     }
 
   return true;