summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDodji Seketeli <dodji@redhat.com>2022-02-10 17:43:38 +0100
committerDodji Seketeli <dodji@redhat.com>2022-03-02 17:24:36 +0100
commitbfd557040376d4e82e4e684f3745f1e55bafdd9b (patch)
treea3366dc73935bbbba059ccac23fa130c1b393281
parentir: Remove obsolete comment from enumerator equal operator (diff)
downloadlibabigail-bfd557040376d4e82e4e684f3745f1e55bafdd9b.tar.gz
libabigail-bfd557040376d4e82e4e684f3745f1e55bafdd9b.tar.bz2
libabigail-bfd557040376d4e82e4e684f3745f1e55bafdd9b.tar.xz
Bug 26646 - unexpected declaration-only types (part 2)
This patch addresses the comment https://sourceware.org/bugzilla/show_bug.cgi?id=26646#c15 of the reported problem. The core of the problem seems to be that when compare_dies compares two DW_TAG_{structure,union}_type, it "gives up" when the comparison stack contains more than 5 such DIEs being compared. Giving up means that it considers the two DIEs to be equivalent if they have the same size and kind, basically. This is to avoid infinite loops or too long loops that we've seen with artificial DWARF input generated by fuzzers. This patch fixes that by better using the "aggregates_being_compared" data structure that is meant to prevent looping infinitely over aggregate DIEs that might be recursively defined. That data structure now contains the DWARF offset pairs of the DIEs being compared, rather than their "string representation". Lookups in that data structure should now be faster and more precise. The artificial limit of the comparison stack not having more than 5 DIEs is now lifted. * src/abg-dwarf-reader.cc (struct dwarf_offset_pair_hash) (dwarf_offset_pair_set_type): Define new type. (die_offset, has_offset_pair, insert_offset_pair) (erase_offset_pair): Define new static helper functions. (compare_dies): Use a set of DWARF offsets for the 'aggregates_being_compared' data structure, rather than a set of string representation of the DIEs. Always look at the size of the types being compared first so that we can get out quickly if they differ. For DIEs of DW_TAG_{union,struct}_type kind, don't limit the depth of the stack of DIEs being compared to 5; so we don't consider two types as being equal just because the depth of the stack being compared is 5 and the two types have the same size and are equal. Hopefully things don't take too long. Signed-off-by: Dodji Seketeli <dodji@redhat.com>
-rw-r--r--src/abg-dwarf-reader.cc134
1 files changed, 97 insertions, 37 deletions
diff --git a/src/abg-dwarf-reader.cc b/src/abg-dwarf-reader.cc
index 53b5845d..b35e6c98 100644
--- a/src/abg-dwarf-reader.cc
+++ b/src/abg-dwarf-reader.cc
@@ -161,7 +161,18 @@ typedef unordered_map<GElf_Addr, elf_symbol_sptr> addr_elf_symbol_sptr_map_type;
161/// Convenience typedef for a set of ELF addresses. 161/// Convenience typedef for a set of ELF addresses.
162typedef unordered_set<GElf_Addr> address_set_type; 162typedef unordered_set<GElf_Addr> address_set_type;
163 163
164typedef unordered_set<interned_string, hash_interned_string> istring_set_type; 164/// A hasher for a pair of Dwarf_Off. This is used as a hasher for
165/// the type @ref dwarf_offset_pair_set_type.
166struct dwarf_offset_pair_hash
167{
168 size_t
169 operator()(const std::pair<Dwarf_Off, Dwarf_Off>& p) const
170 {return abigail::hashing::combine_hashes(p.first, p.second);}
171};// end struct dwarf_offset_pair_hash
172
173typedef unordered_set<std::pair<Dwarf_Off,
174 Dwarf_Off>,
175 dwarf_offset_pair_hash> dwarf_offset_pair_set_type;
165 176
166/// Convenience typedef for a shared pointer to an @ref address_set_type. 177/// Convenience typedef for a shared pointer to an @ref address_set_type.
167typedef shared_ptr<address_set_type> address_set_sptr; 178typedef shared_ptr<address_set_type> address_set_sptr;
@@ -297,6 +308,12 @@ get_scope_die(const read_context& ctxt,
297 size_t where_offset, 308 size_t where_offset,
298 Dwarf_Die& scope_die); 309 Dwarf_Die& scope_die);
299 310
311static Dwarf_Off
312die_offset(Dwarf_Die* die);
313
314static Dwarf_Off
315die_offset(const Dwarf_Die* die);
316
300static bool 317static bool
301die_is_anonymous(const Dwarf_Die* die); 318die_is_anonymous(const Dwarf_Die* die);
302 319
@@ -6230,6 +6247,24 @@ void
6230set_do_log(read_context& ctxt, bool f) 6247set_do_log(read_context& ctxt, bool f)
6231{ctxt.do_log(f);} 6248{ctxt.do_log(f);}
6232 6249
6250/// Get the offset of a DIE
6251///
6252/// @param die the DIE to consider.
6253///
6254/// @return the offset of the DIE.
6255static Dwarf_Off
6256die_offset(Dwarf_Die* die)
6257{return dwarf_dieoffset(die);}
6258
6259/// Get the offset of a DIE
6260///
6261/// @param die the DIE to consider.
6262///
6263/// @return the offset of the DIE.
6264static Dwarf_Off
6265die_offset(const Dwarf_Die* die)
6266{return die_offset(const_cast<Dwarf_Die*>(die));}
6267
6233/// Test if a given DIE is anonymous 6268/// Test if a given DIE is anonymous
6234/// 6269///
6235/// @param die the DIE to consider. 6270/// @param die the DIE to consider.
@@ -10097,6 +10132,50 @@ fn_die_equal_by_linkage_name(const read_context &ctxt,
10097 && llinkage_name == rlinkage_name); 10132 && llinkage_name == rlinkage_name);
10098} 10133}
10099 10134
10135/// Test if the pair of offset {p1,p2} is present in a set.
10136///
10137/// @param set the set of pairs of DWARF offsets to consider.
10138///
10139/// @param p1 the first value of the pair.
10140///
10141/// @param p2 the second value of the pair.
10142///
10143/// @return if the pair {p1,p2} is present in the set.
10144static bool
10145has_offset_pair(const dwarf_offset_pair_set_type& set,
10146 Dwarf_Off p1, Dwarf_Off p2)
10147{
10148 if (set.find(std::make_pair(p1, p2)) != set.end())
10149 return true;
10150 return false;
10151}
10152
10153/// Insert a new pair of offset into the set of pair.
10154///
10155/// @param set the set of pairs of DWARF offsets to consider.
10156///
10157/// @param p1 the first value of the pair.
10158///
10159/// @param p2 the second value of the pair.
10160static void
10161insert_offset_pair(dwarf_offset_pair_set_type& set, Dwarf_Off p1, Dwarf_Off p2)
10162{set.insert(std::make_pair(p1, p2));}
10163
10164/// Erase a pair of DWARF offset from a set of pairs.
10165///
10166///
10167/// @param set the set of pairs of DWARF offsets to consider.
10168///
10169/// @param p1 the first value of the pair.
10170///
10171/// @param p2 the second value of the pair.
10172static void
10173erase_offset_pair(dwarf_offset_pair_set_type& set, Dwarf_Off p1, Dwarf_Off p2)
10174{
10175 std::pair<Dwarf_Off, Dwarf_Off> p(p1, p2);
10176 set.erase(p);
10177}
10178
10100/// Compare two DIEs emitted by a C compiler. 10179/// Compare two DIEs emitted by a C compiler.
10101/// 10180///
10102/// @param ctxt the read context used to load the DWARF information. 10181/// @param ctxt the read context used to load the DWARF information.
@@ -10123,7 +10202,7 @@ fn_die_equal_by_linkage_name(const read_context &ctxt,
10123static bool 10202static bool
10124compare_dies(const read_context& ctxt, 10203compare_dies(const read_context& ctxt,
10125 const Dwarf_Die *l, const Dwarf_Die *r, 10204 const Dwarf_Die *l, const Dwarf_Die *r,
10126 istring_set_type& aggregates_being_compared, 10205 dwarf_offset_pair_set_type& aggregates_being_compared,
10127 bool update_canonical_dies_on_the_fly) 10206 bool update_canonical_dies_on_the_fly)
10128{ 10207{
10129 ABG_ASSERT(l); 10208 ABG_ASSERT(l);
@@ -10268,23 +10347,15 @@ compare_dies(const read_context& ctxt,
10268 case DW_TAG_structure_type: 10347 case DW_TAG_structure_type:
10269 case DW_TAG_union_type: 10348 case DW_TAG_union_type:
10270 { 10349 {
10271 interned_string ln = ctxt.get_die_pretty_type_representation(l, 0); 10350 if (has_offset_pair(aggregates_being_compared,
10272 interned_string rn = ctxt.get_die_pretty_type_representation(r, 0); 10351 die_offset(l), die_offset(r)))
10273
10274 if ((aggregates_being_compared.find(ln)
10275 != aggregates_being_compared.end())
10276 || (aggregates_being_compared.find(rn)
10277 != aggregates_being_compared.end()))
10278 result = true; 10352 result = true;
10279 else if (!compare_as_decl_dies(l, r)) 10353 else if (!compare_as_decl_dies(l, r) || !compare_as_type_dies(l, r))
10280 result = false;
10281 else if (!compare_as_type_dies(l, r))
10282 result = false; 10354 result = false;
10283 else 10355 else
10284 { 10356 {
10285 aggregates_being_compared.insert(ln); 10357 insert_offset_pair(aggregates_being_compared,
10286 aggregates_being_compared.insert(rn); 10358 die_offset(l), die_offset(r));
10287
10288 Dwarf_Die l_member, r_member; 10359 Dwarf_Die l_member, r_member;
10289 bool found_l_member, found_r_member; 10360 bool found_l_member, found_r_member;
10290 for (found_l_member = dwarf_child(const_cast<Dwarf_Die*>(l), 10361 for (found_l_member = dwarf_child(const_cast<Dwarf_Die*>(l),
@@ -10316,8 +10387,8 @@ compare_dies(const read_context& ctxt,
10316 if (found_l_member != found_r_member) 10387 if (found_l_member != found_r_member)
10317 result = false; 10388 result = false;
10318 10389
10319 aggregates_being_compared.erase(ln); 10390 erase_offset_pair(aggregates_being_compared,
10320 aggregates_being_compared.erase(rn); 10391 die_offset(l), die_offset(r));
10321 } 10392 }
10322 } 10393 }
10323 break; 10394 break;
@@ -10402,10 +10473,8 @@ compare_dies(const read_context& ctxt,
10402 interned_string ln = ctxt.get_die_pretty_type_representation(l, 0); 10473 interned_string ln = ctxt.get_die_pretty_type_representation(l, 0);
10403 interned_string rn = ctxt.get_die_pretty_type_representation(r, 0); 10474 interned_string rn = ctxt.get_die_pretty_type_representation(r, 0);
10404 10475
10405 if ((aggregates_being_compared.find(ln) 10476 if (has_offset_pair(aggregates_being_compared, die_offset(l),
10406 != aggregates_being_compared.end()) 10477 die_offset(r)))
10407 || (aggregates_being_compared.find(rn)
10408 != aggregates_being_compared.end()))
10409 { 10478 {
10410 result = true; 10479 result = true;
10411 break; 10480 break;
@@ -10498,8 +10567,8 @@ compare_dies(const read_context& ctxt,
10498 } 10567 }
10499 } 10568 }
10500 10569
10501 aggregates_being_compared.erase(ln); 10570 erase_offset_pair(aggregates_being_compared,
10502 aggregates_being_compared.erase(rn); 10571 die_offset(l), die_offset(r));
10503 } 10572 }
10504 break; 10573 break;
10505 10574
@@ -10535,19 +10604,10 @@ compare_dies(const read_context& ctxt,
10535 Dwarf_Die l_type, r_type; 10604 Dwarf_Die l_type, r_type;
10536 ABG_ASSERT(die_die_attribute(l, DW_AT_type, l_type)); 10605 ABG_ASSERT(die_die_attribute(l, DW_AT_type, l_type));
10537 ABG_ASSERT(die_die_attribute(r, DW_AT_type, r_type)); 10606 ABG_ASSERT(die_die_attribute(r, DW_AT_type, r_type));
10538 if (aggregates_being_compared.size () < 5) 10607 if (!compare_dies(ctxt, &l_type, &r_type,
10539 { 10608 aggregates_being_compared,
10540 if (!compare_dies(ctxt, &l_type, &r_type, 10609 update_canonical_dies_on_the_fly))
10541 aggregates_being_compared, 10610 result = false;
10542 update_canonical_dies_on_the_fly))
10543 result = false;
10544 }
10545 else
10546 {
10547 if (!compare_as_type_dies(&l_type, &r_type)
10548 ||!compare_as_decl_dies(&l_type, &r_type))
10549 return false;
10550 }
10551 } 10611 }
10552 } 10612 }
10553 else 10613 else
@@ -10661,7 +10721,7 @@ compare_dies(const read_context& ctxt,
10661 const Dwarf_Die *r, 10721 const Dwarf_Die *r,
10662 bool update_canonical_dies_on_the_fly) 10722 bool update_canonical_dies_on_the_fly)
10663{ 10723{
10664 istring_set_type aggregates_being_compared; 10724 dwarf_offset_pair_set_type aggregates_being_compared;
10665 return compare_dies(ctxt, l, r, aggregates_being_compared, 10725 return compare_dies(ctxt, l, r, aggregates_being_compared,
10666 update_canonical_dies_on_the_fly); 10726 update_canonical_dies_on_the_fly);
10667} 10727}