[PATCH] D32821: Add DWARF verifiers to verify address ranges are correct and scoped correctly.

David Blaikie via Phabricator via llvm-commits llvm-commits at lists.llvm.org
Tue May 16 11:34:14 PDT 2017


dblaikie added inline comments.


================
Comment at: lib/DebugInfo/DWARF/DWARFVerifier.cpp:139-153
+  if (RHS.Ranges.empty())
+    return false;
+  if (Ranges.empty())
+    return true;
+  size_t LeftSize = Ranges.size();
+  size_t RightSize = RHS.Ranges.size();
+  for (size_t I = 0; I < LeftSize; ++I) {
----------------
dblaikie wrote:
> dblaikie wrote:
> > Can probably implement this with:
> > 
> >   return std::tie(Ranges, Die.getOffset()) < std::tie(RHS.Ranges, RHS.Die.getOffset());
> > 
> > Also - does this need to support < comparison of two entities with exactly the same ranges but a different DIE? When/where does that come up/what behavior is desirable there?
> Still curious about this: does this need to support < comparison of two entities with exactly the same ranges but a different DIE? When/where does that come up/what behavior is desirable there?
Still curious about this


================
Comment at: lib/DebugInfo/DWARF/DWARFVerifier.cpp:60
+    raw_ostream &OS) {
+  Ranges.clear();
+  auto UnsortedRanges = Die.getAddressRanges();
----------------
dblaikie wrote:
> Perhaps this should go in 'insert' which is only called from this function anyway?
Still curious about this


================
Comment at: lib/DebugInfo/DWARF/DWARFVerifier.cpp:70
+          HasErrors = true;
+        return false;
+      });
----------------
dblaikie wrote:
> Guessing this should be 'return true;' - otherwise no elements will ever be removed?
> 
> Is that tested? (what happens if elements aren't removed here? what would that do to the rest of the code/validation?)
While adding an assert is useful - I'm still curious about what would go wrong if/when this wasn't removing the elements it's intended to? Is this purely a performance improvement (if so, it's fine as-is, with the assert). Does this change behavior at all, in a way that matters/is intentional? (eg: does it make follow-on error messages better?) If so, that behavior should be tested.


================
Comment at: lib/DebugInfo/DWARF/DWARFVerifier.cpp:81-84
+  if (HasErrors) {
+    Die.dump(OS, 0);
+    OS << "\n";
+  }
----------------
dblaikie wrote:
> Only dumps one of the two DIEs that are relevant to this situation. It should probably dump both - and at least some test coverage for this to demonstrate the usability of dumping two DIEs, etc.
Still curious about this


================
Comment at: lib/DebugInfo/DWARF/DWARFVerifier.cpp:125-131
+    if (Iter != End && Iter->intersects(R))
+      return true;
+    if (Iter != Begin) {
+      auto Prev = Iter - 1;
+      if (Prev->intersects(R))
+        return true;
+    }
----------------
dblaikie wrote:
> This idiom seems to have appeared in a few places (similar code in DieRangeInfo::insert & sort of similar stuff in 'contains') any chance of factoring that out?
Still curious about this - this code and DieRangeInfo::insert (& similar, though not identical code for 'contains' tests) were duplicate, and now this code is fixed but DieRangeInfo::insert is not. Please refactor so the code's written once, not twice to avoid this kind of divergence/duplication/repeated work.


================
Comment at: lib/DebugInfo/DWARF/DWARFVerifier.cpp:156-160
+  // Die has address ranges so we need to check that its address ranges are
+  // contained in this DieInfo's address ranges except if this is a compile
+  // unit that doesn't have address range(s).
+  bool IsCompileUnit = RI.Die.getTag() == DW_TAG_compile_unit;
+  bool CheckContains = !IsCompileUnit || !RI.Ranges.empty();
----------------
dblaikie wrote:
> Why is a rangeless CU a special case/acceptable here, in comparison to say, a rangeless subprogram or lexical_block?
Still curious about this


================
Comment at: lib/DebugInfo/DWARF/DWARFVerifier.cpp:213-218
+  case DW_TAG_compile_unit:
+    // Set the Unit DIE info.
+    UnitDI.RI.Die = Die;
+    if (UnitDI.RI.extractRangesAndReportErrors(OS))
+      ++NumDebugInfoErrors;
+    break;
----------------
dblaikie wrote:
> Where, if anywhere, does the case of overlapping CUs get handled? That should be an error, right?
Still wondering about this.


================
Comment at: lib/DebugInfo/DWARF/DWARFVerifier.cpp:215-216
+    // Set the Unit DIE info.
+    UnitDI.RI.Die = Die;
+    if (UnitDI.RI.extractRangesAndReportErrors(OS))
+      ++NumDebugInfoErrors;
----------------
dblaikie wrote:
> If the RI is the only part of UnitDI that's used - maybe only have the RI in the first place here?
> 
> But maybe the NOR in UnitDI should be used - that would catch cases where two CUs overlap with each other, right? & then all 3 cases (compile_unit, subprogram, lexical_block) would look quite the same, I think, just operating on different DieInfo objects?
Still curious about this


================
Comment at: lib/DebugInfo/DWARF/DWARFVerifier.cpp:131-133
+  auto Iter = std::upper_bound(Begin, End, RHS.Ranges.front());
+  if (Iter != Begin)
+    --Iter;
----------------
I'd probably skip this - the algorithm's linear anyway & pretty tidy without it. I suppose it catches the common case where they don't overlap at all, but might be better done another way (range lists could keep their max/min bound & shortcircuit here, etc)


================
Comment at: lib/DebugInfo/DWARF/DWARFVerifier.cpp:135-141
+    if (R.End <= Iter->Start)
+      continue;
+    while (Iter != End) {
+      if (Iter->intersects(R))
+        return true;
+      ++Iter;
+    }
----------------
This looks more expensive than what I had in mind - I figured a linear search to find the item, then testing 'intersects', rather than testing intersects on every item along the way.


================
Comment at: lib/DebugInfo/DWARF/DWARFVerifier.cpp:176-177
+
+  // Check if this range overlaps with any previous sibling ranges and make an
+  // error if needed.
+  if (NOR.insertAndReportErrors(OS, DieRI))
----------------
Probably "emit (or report, to match the function name) an error" ("make an error" sounds curious, like maybe it returns an llvm::Error (though even that I'd expect to be described as "returns an Error") that the caller is responsible for emitting to the user, etc)


================
Comment at: lib/DebugInfo/DWARF/DWARFVerifier.cpp:183
+
+Optional<DWARFDie> DWARFVerifier::NonOverlappingRanges::GetOverlappingRangeInfo(
+    const DieRangeInfo &RI) const {
----------------
DWARFDie is already boolean testable - does it need to be wrapped in Optional? Or could this return an invalid DWARFDie to signal the "no overlap" case?


https://reviews.llvm.org/D32821





More information about the llvm-commits mailing list