[Coverage] PR33517: Check for failure to load func records

With PR33517, it became apparent that symbol table creation can fail
when presented with malformed inputs. This patch makes that sort of
error detectable, so llvm-cov etc. can fail more gracefully.

Specifically, we now check that function records loaded from corrupted coverage
mapping data are rejected, e.g when the recorded function name is garbage.

Testing: check-{llvm,clang,profile}, some unit test updates.

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@305767 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Vedant Kumar 2017-06-20 02:05:35 +00:00
parent b9454635c0
commit 9f0d281d87
2 changed files with 42 additions and 16 deletions

View File

@ -200,6 +200,9 @@ Error CoverageMapping::loadFunctionRecord(
const CoverageMappingRecord &Record,
IndexedInstrProfReader &ProfileReader) {
StringRef OrigFuncName = Record.FunctionName;
if (OrigFuncName.empty())
return make_error<CoverageMapError>(coveragemap_error::malformed);
if (Record.Filenames.empty())
OrigFuncName = getFuncNameWithoutPrefix(OrigFuncName);
else

View File

@ -28,6 +28,19 @@ static ::testing::AssertionResult NoError(Error E) {
<< "\n";
}
static ::testing::AssertionResult ErrorEquals(coveragemap_error Expected,
Error E) {
coveragemap_error Found;
std::string FoundMsg;
handleAllErrors(std::move(E), [&](const CoverageMapError &CME) {
Found = CME.get();
FoundMsg = CME.message();
});
if (Expected == Found)
return ::testing::AssertionSuccess();
return ::testing::AssertionFailure() << "error: " << FoundMsg << "\n";
}
namespace llvm {
namespace coverage {
void PrintTo(const Counter &C, ::std::ostream *os) {
@ -232,12 +245,14 @@ struct CoverageMappingTest : ::testing::TestWithParam<std::pair<bool, bool>> {
return CoverageMapping::load(CoverageReaders, *ProfileReader);
}
void loadCoverageMapping(bool EmitFilenames = true) {
Error loadCoverageMapping(bool EmitFilenames = true) {
readProfCounts();
writeAndReadCoverageRegions(EmitFilenames);
auto CoverageOrErr = readOutputFunctions();
ASSERT_TRUE(NoError(CoverageOrErr.takeError()));
if (!CoverageOrErr)
return CoverageOrErr.takeError();
LoadedCoverage = std::move(CoverageOrErr.get());
return Error::success();
}
};
@ -304,7 +319,7 @@ TEST_P(CoverageMappingTest, load_coverage_for_more_than_two_files) {
// in order to preserve that information during possible sorting of CMRs.
addCMR(Counter::getCounter(0), FileNames[I], I, 1, I, 1);
loadCoverageMapping();
NoError(loadCoverageMapping());
for (unsigned I = 0; I < N; ++I) {
CoverageData Data = LoadedCoverage->getCoverageForFile(FileNames[I]);
@ -313,6 +328,14 @@ TEST_P(CoverageMappingTest, load_coverage_for_more_than_two_files) {
}
}
TEST_P(CoverageMappingTest, load_coverage_with_bogus_function_name) {
InstrProfRecord RecordFunc1("", 0x1234, {10});
NoError(ProfileWriter.addRecord(std::move(RecordFunc1)));
startFunction("", 0x1234);
addCMR(Counter::getCounter(0), "foo", 1, 1, 5, 5);
ErrorEquals(coveragemap_error::malformed, loadCoverageMapping());
}
TEST_P(CoverageMappingTest, load_coverage_for_several_functions) {
InstrProfRecord RecordFunc1("func1", 0x1234, {10});
NoError(ProfileWriter.addRecord(std::move(RecordFunc1)));
@ -325,7 +348,7 @@ TEST_P(CoverageMappingTest, load_coverage_for_several_functions) {
startFunction("func2", 0x2345);
addCMR(Counter::getCounter(0), "bar", 2, 2, 6, 6);
loadCoverageMapping();
NoError(loadCoverageMapping());
const auto FunctionRecords = LoadedCoverage->getCoveredFunctions();
EXPECT_EQ(2, std::distance(FunctionRecords.begin(), FunctionRecords.end()));
@ -369,7 +392,7 @@ TEST_P(CoverageMappingTest, basic_coverage_iteration) {
addCMR(Counter::getCounter(1), "file1", 1, 1, 4, 7);
addCMR(Counter::getCounter(2), "file1", 5, 8, 9, 1);
addCMR(Counter::getCounter(3), "file1", 10, 10, 11, 11);
loadCoverageMapping();
NoError(loadCoverageMapping());
CoverageData Data = LoadedCoverage->getCoverageForFile("file1");
std::vector<CoverageSegment> Segments(Data.begin(), Data.end());
@ -386,7 +409,7 @@ TEST_P(CoverageMappingTest, basic_coverage_iteration) {
TEST_P(CoverageMappingTest, uncovered_function) {
startFunction("func", 0x1234);
addCMR(Counter::getZero(), "file1", 1, 2, 3, 4);
loadCoverageMapping();
NoError(loadCoverageMapping());
CoverageData Data = LoadedCoverage->getCoverageForFile("file1");
std::vector<CoverageSegment> Segments(Data.begin(), Data.end());
@ -399,7 +422,7 @@ TEST_P(CoverageMappingTest, uncovered_function_with_mapping) {
startFunction("func", 0x1234);
addCMR(Counter::getCounter(0), "file1", 1, 1, 9, 9);
addCMR(Counter::getCounter(1), "file1", 1, 1, 4, 7);
loadCoverageMapping();
NoError(loadCoverageMapping());
CoverageData Data = LoadedCoverage->getCoverageForFile("file1");
std::vector<CoverageSegment> Segments(Data.begin(), Data.end());
@ -417,7 +440,7 @@ TEST_P(CoverageMappingTest, combine_regions) {
addCMR(Counter::getCounter(0), "file1", 1, 1, 9, 9);
addCMR(Counter::getCounter(1), "file1", 3, 3, 4, 4);
addCMR(Counter::getCounter(2), "file1", 3, 3, 4, 4);
loadCoverageMapping();
NoError(loadCoverageMapping());
CoverageData Data = LoadedCoverage->getCoverageForFile("file1");
std::vector<CoverageSegment> Segments(Data.begin(), Data.end());
@ -436,7 +459,7 @@ TEST_P(CoverageMappingTest, restore_combined_counter_after_nested_region) {
addCMR(Counter::getCounter(0), "file1", 1, 1, 9, 9);
addCMR(Counter::getCounter(1), "file1", 1, 1, 9, 9);
addCMR(Counter::getCounter(2), "file1", 3, 3, 5, 5);
loadCoverageMapping();
NoError(loadCoverageMapping());
CoverageData Data = LoadedCoverage->getCoverageForFile("file1");
std::vector<CoverageSegment> Segments(Data.begin(), Data.end());
@ -460,7 +483,7 @@ TEST_P(CoverageMappingTest, dont_combine_expansions) {
addCMR(Counter::getCounter(1), "file1", 3, 3, 4, 4);
addCMR(Counter::getCounter(1), "include1", 6, 6, 7, 7);
addExpansionCMR("file1", "include1", 3, 3, 4, 4);
loadCoverageMapping();
NoError(loadCoverageMapping());
CoverageData Data = LoadedCoverage->getCoverageForFile("file1");
std::vector<CoverageSegment> Segments(Data.begin(), Data.end());
@ -483,7 +506,7 @@ TEST_P(CoverageMappingTest, combine_expansions) {
addExpansionCMR("file", "include1", 3, 1, 3, 5);
addExpansionCMR("file", "include2", 3, 1, 3, 5);
loadCoverageMapping();
NoError(loadCoverageMapping());
CoverageData Data = LoadedCoverage->getCoverageForFile("file");
std::vector<CoverageSegment> Segments(Data.begin(), Data.end());
@ -500,7 +523,7 @@ TEST_P(CoverageMappingTest, strip_filename_prefix) {
startFunction("file1:func", 0x1234);
addCMR(Counter::getCounter(0), "file1", 1, 1, 9, 9);
loadCoverageMapping();
NoError(loadCoverageMapping());
std::vector<std::string> Names;
for (const auto &Func : LoadedCoverage->getCoveredFunctions())
@ -515,7 +538,7 @@ TEST_P(CoverageMappingTest, strip_unknown_filename_prefix) {
startFunction("<unknown>:func", 0x1234);
addCMR(Counter::getCounter(0), "", 1, 1, 9, 9);
loadCoverageMapping(/*EmitFilenames=*/false);
NoError(loadCoverageMapping(/*EmitFilenames=*/false));
std::vector<std::string> Names;
for (const auto &Func : LoadedCoverage->getCoveredFunctions())
@ -538,7 +561,7 @@ TEST_P(CoverageMappingTest, dont_detect_false_instantiations) {
addCMR(Counter::getCounter(0), "expanded", 1, 1, 1, 10);
addExpansionCMR("main", "expanded", 9, 1, 9, 5);
loadCoverageMapping();
NoError(loadCoverageMapping());
std::vector<const FunctionRecord *> Instantiations =
LoadedCoverage->getInstantiations("expanded");
@ -553,7 +576,7 @@ TEST_P(CoverageMappingTest, load_coverage_for_expanded_file) {
addCMR(Counter::getCounter(0), "expanded", 1, 1, 1, 10);
addExpansionCMR("main", "expanded", 4, 1, 4, 5);
loadCoverageMapping();
NoError(loadCoverageMapping());
CoverageData Data = LoadedCoverage->getCoverageForFile("expanded");
std::vector<CoverageSegment> Segments(Data.begin(), Data.end());
@ -572,7 +595,7 @@ TEST_P(CoverageMappingTest, skip_duplicate_function_record) {
startFunction("func", 0x1234);
addCMR(Counter::getCounter(0), "file1", 1, 1, 9, 9);
loadCoverageMapping();
NoError(loadCoverageMapping());
auto Funcs = LoadedCoverage->getCoveredFunctions();
unsigned NumFuncs = std::distance(Funcs.begin(), Funcs.end());