dwarf-reader: Bug 26908 - don't crash on empty DW_TAG_partial_unit
Commit Message
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(-)
@@ -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.