From 2417efb2b7619ed2a2bd089d267833ee9d171eea Mon Sep 17 00:00:00 2001 From: Dodji Seketeli Date: Mon, 30 Nov 2020 05:53:11 +0100 Subject: [PATCH] dwarf-reader: Bug 26908 - don't crash on empty DW_TAG_partial_unit 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 --- src/abg-dwarf-reader.cc | 49 ++++++++++++++++++++++++++++++++++------- 1 file changed, 41 insertions(+), 8 deletions(-) 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(&imported_die), - &imported_unit_child); + ABG_ASSERT(dwarf_child(const_cast(&imported_die), + &imported_unit_child) == 0); + imported_unit_child_off = dwarf_dieoffset(const_cast(&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(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. -- 2.43.5