Index: include/llvm/ProfileData/Coverage/CoverageMappingReader.h =================================================================== --- include/llvm/ProfileData/Coverage/CoverageMappingReader.h +++ include/llvm/ProfileData/Coverage/CoverageMappingReader.h @@ -44,18 +44,26 @@ /// \brief A file format agnostic iterator over coverage mapping data. class CoverageMappingIterator : public std::iterator { - CoverageMappingReader *Reader = nullptr; + CoverageMappingReader *Reader; CoverageMappingRecord Record; + coveragemap_error ReadErr; void increment(); public: - CoverageMappingIterator() = default; + CoverageMappingIterator() + : Reader(nullptr), Record(), ReadErr(coveragemap_error::success) {} - CoverageMappingIterator(CoverageMappingReader *Reader) : Reader(Reader) { + CoverageMappingIterator(CoverageMappingReader *Reader) + : Reader(Reader), Record(), ReadErr(coveragemap_error::success) { increment(); } + ~CoverageMappingIterator() { + if (ReadErr != coveragemap_error::success) + llvm_unreachable("Unexpected error in coverage mapping iterator"); + } + CoverageMappingIterator &operator++() { increment(); return *this; @@ -66,8 +74,22 @@ bool operator!=(const CoverageMappingIterator &RHS) { return Reader != RHS.Reader; } - CoverageMappingRecord &operator*() { return Record; } - CoverageMappingRecord *operator->() { return &Record; } + Expected operator*() { + if (ReadErr != coveragemap_error::success) { + auto E = make_error(ReadErr); + ReadErr = coveragemap_error::success; + return std::move(E); + } + return Record; + } + Expected operator->() { + if (ReadErr != coveragemap_error::success) { + auto E = make_error(ReadErr); + ReadErr = coveragemap_error::success; + return std::move(E); + } + return &Record; + } }; class CoverageMappingReader { Index: lib/ProfileData/Coverage/CoverageMapping.cpp =================================================================== --- lib/ProfileData/Coverage/CoverageMapping.cpp +++ lib/ProfileData/Coverage/CoverageMapping.cpp @@ -250,10 +250,15 @@ IndexedInstrProfReader &ProfileReader) { auto Coverage = std::unique_ptr(new CoverageMapping()); - for (const auto &CoverageReader : CoverageReaders) - for (const auto &Record : *CoverageReader) + for (const auto &CoverageReader : CoverageReaders) { + for (auto RecordOrErr : *CoverageReader) { + if (Error E = RecordOrErr.takeError()) + return std::move(E); + const auto &Record = *RecordOrErr; if (Error E = Coverage->loadFunctionRecord(Record, ProfileReader)) return std::move(E); + } + } return std::move(Coverage); } Index: lib/ProfileData/Coverage/CoverageMappingReader.cpp =================================================================== --- lib/ProfileData/Coverage/CoverageMappingReader.cpp +++ lib/ProfileData/Coverage/CoverageMappingReader.cpp @@ -49,16 +49,18 @@ #define DEBUG_TYPE "coverage-mapping" void CoverageMappingIterator::increment() { + if (ReadErr != coveragemap_error::success) + return; + // Check if all the records were read or if an error occurred while reading // the next record. - if (auto E = Reader->readNextRecord(Record)) { + if (auto E = Reader->readNextRecord(Record)) handleAllErrors(std::move(E), [&](const CoverageMapError &CME) { if (CME.get() == coveragemap_error::eof) *this = CoverageMappingIterator(); else - llvm_unreachable("Unexpected error in coverage mapping iterator"); + ReadErr = CME.get(); }); - } } Error RawCoverageReader::readULEB128(uint64_t &Result) { @@ -238,9 +240,12 @@ dbgs() << "\n"; }); - MappingRegions.push_back(CounterMappingRegion( - C, InferredFileID, ExpandedFileID, LineStart, ColumnStart, - LineStart + NumLines, ColumnEnd, Kind)); + auto CMR = CounterMappingRegion(C, InferredFileID, ExpandedFileID, + LineStart, ColumnStart, + LineStart + NumLines, ColumnEnd, Kind); + if (CMR.startLoc() > CMR.endLoc()) + return make_error(coveragemap_error::malformed); + MappingRegions.push_back(CMR); } return Error::success(); } Index: lib/ProfileData/Coverage/CoverageMappingWriter.cpp =================================================================== --- lib/ProfileData/Coverage/CoverageMappingWriter.cpp +++ lib/ProfileData/Coverage/CoverageMappingWriter.cpp @@ -116,6 +116,13 @@ } void CoverageMappingWriter::write(raw_ostream &OS) { + // Check that we don't have any bogus regions. + assert(all_of(MappingRegions, + [](const CounterMappingRegion &CMR) { + return CMR.startLoc() <= CMR.endLoc(); + }) && + "Source region does not begin before it ends"); + // Sort the regions in an ascending order by the file id and the starting // location. Sort by region kinds to ensure stable order for tests. std::stable_sort( Index: test/tools/llvm-cov/Inputs/lineExecutionCounts.json =================================================================== --- test/tools/llvm-cov/Inputs/lineExecutionCounts.json +++ test/tools/llvm-cov/Inputs/lineExecutionCounts.json @@ -14,7 +14,7 @@ // CHECK-SAME: "summary":{ // CHECK-SAME: "lines":{"count":20,"covered":16,"percent":80}, // CHECK-SAME: "functions":{"count":1,"covered":1,"percent":100}, -// CHECK-SAME: "regions":{"count":10,"covered":7,"notcovered":3,"percent":70}}} +// CHECK-SAME: "regions":{"count":11,"covered":8,"notcovered":3,"percent":72}}} // Close Files Array // CHECK-SAME: ], @@ -33,7 +33,7 @@ // CHECK-SAME: "lines":{"count":20,"covered":16,"percent":80}, // CHECK-SAME: "functions":{"count":1,"covered":1,"percent":100}, // CHECK-SAME: "instantiations":{"count":1,"covered":1,"percent":100}, -// CHECK-SAME: "regions":{"count":10,"covered":7,"notcovered":3,"percent":70}} +// CHECK-SAME: "regions":{"count":11,"covered":8,"notcovered":3,"percent":72}} // Close the export object, data array, and root object // CHECK-SAME: }]} Index: test/tools/llvm-cov/showLineExecutionCounts.cpp =================================================================== --- test/tools/llvm-cov/showLineExecutionCounts.cpp +++ test/tools/llvm-cov/showLineExecutionCounts.cpp @@ -50,7 +50,7 @@ // HTML:
[[@LINE-44]]
161
int main() {
 // HTML: 
[[@LINE-44]]
161
  int x = 0
 // HTML: 
[[@LINE-44]]
161
-// HTML: 
[[@LINE-44]]
161
  if (x) {
+// HTML: 
[[@LINE-44]]
161
  if (x)
 // HTML: 
[[@LINE-44]]
0
 // HTML: 
[[@LINE-44]]
161
  }
 // HTML: 
[[@LINE-44]]
161
    x = 1;
@@ -62,7 +62,7 @@
 // HTML: 
[[@LINE-44]]
161
 // HTML: 
[[@LINE-44]]
161
  x = x < 10
 // HTML: 
[[@LINE-44]]
161
  x = x > 10
-// HTML: 
[[@LINE-44]]
0
        x - 1:
+// HTML: 
[[@LINE-44]]
0
 x - 1:
 // HTML: 
[[@LINE-44]]
161
        x + 1;
 // HTML: 
[[@LINE-44]]
161
 // HTML: 
[[@LINE-44]]
161
  return 0;
@@ -91,5 +91,5 @@
 // HTML-INDEX: 
 // HTML-INDEX: 80.00% (16/20)
 // HTML-INDEX: 
-// HTML-INDEX: 70.00% (7/10)
+// HTML-INDEX: 72.73% (8/11)
 // HTML-INDEX: TOTALS
Index: test/tools/llvm-cov/warnings.h
===================================================================
--- test/tools/llvm-cov/warnings.h
+++ test/tools/llvm-cov/warnings.h
@@ -11,3 +11,6 @@
 
 // FAKE-FUNC-STDOUT-NOT: warning: Could not read coverage for '{{.*}}'.
 // FAKE-FUNC-STDERR: Could not read coverage for '{{.*}}'.
+
+// RUN: not llvm-cov report %S/Inputs/malformedRegions.covmapping -instr-profile %S/Inputs/elf_binary_comdat.profdata 2>&1 | FileCheck %s -check-prefix=MALFORMED-REGION
+// MALFORMED-REGION: malformedRegions.covmapping: Failed to load coverage: Malformed coverage data