diff --git a/llvm/include/llvm/ProfileData/InstrProf.h b/llvm/include/llvm/ProfileData/InstrProf.h --- a/llvm/include/llvm/ProfileData/InstrProf.h +++ b/llvm/include/llvm/ProfileData/InstrProf.h @@ -290,6 +290,7 @@ truncated, malformed, unknown_function, + invalid_merge, hash_mismatch, count_mismatch, counter_overflow, diff --git a/llvm/include/llvm/ProfileData/InstrProfWriter.h b/llvm/include/llvm/ProfileData/InstrProfWriter.h --- a/llvm/include/llvm/ProfileData/InstrProfWriter.h +++ b/llvm/include/llvm/ProfileData/InstrProfWriter.h @@ -64,11 +64,13 @@ function_ref Warn); /// Write the profile to \c OS - void write(raw_fd_ostream &OS); + Error write(raw_fd_ostream &OS); /// Write the profile in text format to \c OS Error writeText(raw_fd_ostream &OS); + Error validateRecord(const InstrProfRecord &Func); + /// Write \c Record in text format to \c OS static void writeRecordInText(StringRef Name, uint64_t Hash, const InstrProfRecord &Counters, @@ -114,7 +116,8 @@ void addRecord(StringRef Name, uint64_t Hash, InstrProfRecord &&I, uint64_t Weight, function_ref Warn); bool shouldEncodeData(const ProfilingData &PD); - void writeImpl(ProfOStream &OS); + + Error writeImpl(ProfOStream &OS); }; } // end namespace llvm diff --git a/llvm/lib/ProfileData/InstrProf.cpp b/llvm/lib/ProfileData/InstrProf.cpp --- a/llvm/lib/ProfileData/InstrProf.cpp +++ b/llvm/lib/ProfileData/InstrProf.cpp @@ -18,6 +18,7 @@ #include "llvm/ADT/StringExtras.h" #include "llvm/ADT/StringRef.h" #include "llvm/ADT/Triple.h" +#include "llvm/Config/config.h" #include "llvm/IR/Constant.h" #include "llvm/IR/Constants.h" #include "llvm/IR/Function.h" @@ -95,6 +96,10 @@ return "Truncated profile data"; case instrprof_error::malformed: return "Malformed instrumentation profile data"; + case instrprof_error::invalid_merge: + return "Merge created invalid profile. Please file a bug " + "at: " BUG_REPORT_URL + " and include the profraw files that caused this error."; case instrprof_error::unknown_function: return "No profile data available for function"; case instrprof_error::hash_mismatch: diff --git a/llvm/lib/ProfileData/InstrProfWriter.cpp b/llvm/lib/ProfileData/InstrProfWriter.cpp --- a/llvm/lib/ProfileData/InstrProfWriter.cpp +++ b/llvm/lib/ProfileData/InstrProfWriter.cpp @@ -285,7 +285,7 @@ TheSummary->setEntry(I, Res[I]); } -void InstrProfWriter::writeImpl(ProfOStream &OS) { +Error InstrProfWriter::writeImpl(ProfOStream &OS) { using namespace IndexedInstrProf; OnDiskChainedHashTableGenerator Generator; @@ -365,6 +365,11 @@ } InfoObj->CSSummaryBuilder = nullptr; + for (const auto &I : FunctionData) + for (const auto &F : I.getValue()) + if (Error E = validateRecord(F.second)) + return E; + // Now do the final patch: PatchItem PatchItems[] = { // Patch the Header.HashOffset field. @@ -376,12 +381,14 @@ (int)CSSummarySize}}; OS.patch(PatchItems, sizeof(PatchItems) / sizeof(*PatchItems)); + + return Error::success(); } -void InstrProfWriter::write(raw_fd_ostream &OS) { +Error InstrProfWriter::write(raw_fd_ostream &OS) { // Write the hash table. ProfOStream POS(OS); - writeImpl(POS); + return writeImpl(POS); } std::unique_ptr InstrProfWriter::writeBuffer() { @@ -389,7 +396,8 @@ raw_string_ostream OS(Data); ProfOStream POS(OS); // Write the hash table. - writeImpl(POS); + if (Error E = writeImpl(POS)) + return nullptr; // Return this in an aligned memory buffer. return MemoryBuffer::getMemBufferCopy(Data); } @@ -399,6 +407,27 @@ #include "llvm/ProfileData/InstrProfData.inc" }; +Error InstrProfWriter::validateRecord(const InstrProfRecord &Func) { + for (uint32_t VK = 0; VK <= IPVK_Last; VK++) { + uint32_t NS = Func.getNumValueSites(VK); + if (!NS) + continue; + for (uint32_t S = 0; S < NS; S++) { + uint32_t ND = Func.getNumValueDataForSite(VK, S); + std::unique_ptr VD = Func.getValueForSite(VK, S); + bool WasZero = false; + for (uint32_t I = 0; I < ND; I++) + if ((VK != IPVK_IndirectCallTarget) && (VD[I].Value == 0)) { + if (WasZero) + return make_error(instrprof_error::invalid_merge); + WasZero = true; + } + } + } + + return Error::success(); +} + void InstrProfWriter::writeRecordInText(StringRef Name, uint64_t Hash, const InstrProfRecord &Func, InstrProfSymtab &Symtab, @@ -470,6 +499,8 @@ for (const auto &record : OrderedFuncData) { const StringRef &Name = record.first; const FuncPair &Func = record.second; + if (Error E = validateRecord(Func.second)) + return E; writeRecordInText(Name, Func.first, Func.second, Symtab, OS); } diff --git a/llvm/test/tools/llvm-profdata/invalid-profile-gen-zeros.proftext b/llvm/test/tools/llvm-profdata/invalid-profile-gen-zeros.proftext new file mode 100644 --- /dev/null +++ b/llvm/test/tools/llvm-profdata/invalid-profile-gen-zeros.proftext @@ -0,0 +1,30 @@ +# RUN: not llvm-profdata merge --text -j 4 %s %s %s %s -o %t 2>&1 | FileCheck %s +# RUN: not llvm-profdata merge --binary -j 4 %s %s %s %s -o %t 2>&1 | FileCheck %s +# IR level Instrumentation Flag +# CHECK: Merge created invalid profile. Please file a bug at: +:ir +foo +# Func Hash: +35277121310 +# Num Counters: +3 +# Counter Values: +20 +556 +1 +# Num Value Kinds: +1 +# ValueKind = IPVK_MemOPSize: +1 +# NumValueSites: +1 +9 +0:99 +0:88 +3:77 +9:72 +4:66 +5:55 +6:44 +7:33 +8:22 diff --git a/llvm/tools/llvm-profdata/llvm-profdata.cpp b/llvm/tools/llvm-profdata/llvm-profdata.cpp --- a/llvm/tools/llvm-profdata/llvm-profdata.cpp +++ b/llvm/tools/llvm-profdata/llvm-profdata.cpp @@ -304,7 +304,8 @@ if (Error E = Writer.writeText(Output)) exitWithError(std::move(E)); } else { - Writer.write(Output); + if (Error E = Writer.write(Output)) + exitWithError(std::move(E)); } }