dwarf-reader: Bug 26908 - don't crash on empty DW_TAG_partial_unit

Message ID 87mtyz5qhl.fsf@redhat.com
State New
Headers
Series dwarf-reader: Bug 26908 - don't crash on empty DW_TAG_partial_unit |

Commit Message

Dodji Seketeli Nov. 30, 2020, 6:05 a.m. UTC
  Hello,

Sometimes a DW_TAG_partial_unit (imported via a DW_TAG_imported_unit)
has no children node.  That means the the DW_TAG_partial_unit has no
sub-tree.

In those cases, the dwarf-reader crashes when
ctxt.build_die_parent_relations_under tries to record the point at
which the sub-tree (which is non-existent here) of the partial unit is
imported by the DW_TAG_imported_unit DIE.

This patch avoids crashing in those cases.  As this problem is
reported on libclang-cpp.so (on Fedora 33) which takes "abidw --abidiff"
five hours and ~ 20GB of ram to complete at this point (on a power7 box)
this patch doesn't have a regression test attached.

	* src/abg-dwarf-reader.cc (die_has_children): Define new static
	function.
	(read_context::build_die_parent_relations_under): Do not try to
	instantiate an imported_unit_point type for an imported unit with
	no children node.
	(imported_unit_point::imported_unit_point): Assert that the
	imported die has a sub-tree.
	(imported_unit_point::imported_unit_point): Remove useless spaces.

Signed-off-by: Dodji Seketeli <dodji@redhat.com>

Apply to master.

---
 src/abg-dwarf-reader.cc | 49 ++++++++++++++++++++++++++++++++++-------
 1 file changed, 41 insertions(+), 8 deletions(-)
  

Patch

diff --git a/src/abg-dwarf-reader.cc b/src/abg-dwarf-reader.cc
index fd1372a3..61845a63 100644
--- a/src/abg-dwarf-reader.cc
+++ b/src/abg-dwarf-reader.cc
@@ -220,7 +220,7 @@  struct imported_unit_point
   Dwarf_Off	imported_unit_child_off;
 
   /// Default constructor for @ref the type imported_unit_point.
-  imported_unit_point ()
+  imported_unit_point()
     : offset_of_import(),
       imported_unit_die_source(PRIMARY_DEBUG_INFO_DIE_SOURCE),
       imported_unit_die_off(),
@@ -232,7 +232,7 @@  struct imported_unit_point
   ///
   /// @param import_off the offset of the point at which the unit has
   /// been imported.
-  imported_unit_point (Dwarf_Off import_off)
+  imported_unit_point(Dwarf_Off import_off)
     : offset_of_import(import_off),
       imported_unit_die_source(PRIMARY_DEBUG_INFO_DIE_SOURCE),
       imported_unit_die_off(),
@@ -248,9 +248,9 @@  struct imported_unit_point
   /// @param from where the imported DIE comes from.
   ///
   /// @param imported_die the die of the unit that has been imported.
-  imported_unit_point (Dwarf_Off	import_off,
-		       const Dwarf_Die& imported_die,
-		       die_source from)
+  imported_unit_point(Dwarf_Off	import_off,
+		      const Dwarf_Die& imported_die,
+		      die_source from)
     : offset_of_import(import_off),
       imported_unit_die_source(from),
       imported_unit_die_off(dwarf_dieoffset
@@ -260,8 +260,9 @@  struct imported_unit_point
   {
     Dwarf_Die imported_unit_child;
 
-    dwarf_child(const_cast<Dwarf_Die*>(&imported_die),
-		&imported_unit_child);
+    ABG_ASSERT(dwarf_child(const_cast<Dwarf_Die*>(&imported_die),
+			   &imported_unit_child) == 0);
+
     imported_unit_child_off =
       dwarf_dieoffset(const_cast<Dwarf_Die*>(&imported_unit_child));
 
@@ -355,6 +356,9 @@  static bool
 die_has_object_pointer(const Dwarf_Die* die,
 		       Dwarf_Die& object_pointer);
 
+static bool
+die_has_children(const Dwarf_Die* die);
+
 static bool
 die_this_pointer_from_object_pointer(Dwarf_Die* die,
 				     Dwarf_Die& this_pointer);
@@ -7710,7 +7714,18 @@  public:
 	if (dwarf_tag(&child) == DW_TAG_imported_unit)
 	  {
 	    Dwarf_Die imported_unit;
-	    if (die_die_attribute(&child, DW_AT_import, imported_unit))
+	    if (die_die_attribute(&child, DW_AT_import, imported_unit)
+		// If the imported_unit has a sub-tree, let's record
+		// this point at which the sub-tree is imported into
+		// the current debug info.
+		//
+		// Otherwise, if the imported_unit has no sub-tree,
+		// there is no point in recording where a non-existent
+		// sub-tree is being imported.
+		//
+		// Note that the imported_unit_points_type type below
+		// expects the imported_unit to have a sub-tree.
+		&& die_has_children(&imported_unit))
 	      {
 		die_source imported_unit_die_source = NO_DEBUG_INFO_DIE_SOURCE;
 		ABG_ASSERT(get_die_source(imported_unit, imported_unit_die_source));
@@ -8906,6 +8921,24 @@  die_has_object_pointer(const Dwarf_Die* die, Dwarf_Die& object_pointer)
   return false;
 }
 
+/// Test if a DIE has children DIEs.
+///
+/// @param die the DIE to consider.
+///
+/// @return true iff @p DIE has at least one child node.
+static bool
+die_has_children(const Dwarf_Die* die)
+{
+  if (!die)
+    return false;
+
+  Dwarf_Die child;
+  if (dwarf_child(const_cast<Dwarf_Die*>(die), &child) == 0)
+    return true;
+
+  return false;
+}
+
 /// When given the object pointer DIE of a function type or member
 /// function DIE, this function returns the "this" pointer that points
 /// to the associated class.