Index: include/llvm/ProfileData/InstrProfReader.h =================================================================== --- include/llvm/ProfileData/InstrProfReader.h +++ include/llvm/ProfileData/InstrProfReader.h @@ -111,7 +111,10 @@ TextInstrProfReader(std::unique_ptr DataBuffer_) : DataBuffer(std::move(DataBuffer_)), Line(*DataBuffer, true, '#') {} - /// Read the header. + /// Return true if the given buffer is in text instrprof format. + static bool hasFormat(const MemoryBuffer &Buffer); + + /// Read the header. std::error_code readHeader() override { return success(); } /// Read a single record. std::error_code readNextRecord(InstrProfRecord &Record) override; Index: include/llvm/ProfileData/SampleProfReader.h =================================================================== --- include/llvm/ProfileData/SampleProfReader.h +++ include/llvm/ProfileData/SampleProfReader.h @@ -292,6 +292,9 @@ /// \brief Read sample profiles from the associated file. std::error_code read() override; + + /// \brief Return true if \p Buffer is in the format supported by this class. + static bool hasFormat(const MemoryBuffer &Buffer); }; class SampleProfileReaderBinary : public SampleProfileReader { Index: lib/ProfileData/InstrProf.cpp =================================================================== --- lib/ProfileData/InstrProf.cpp +++ lib/ProfileData/InstrProf.cpp @@ -33,19 +33,19 @@ case instrprof_error::eof: return "End of File"; case instrprof_error::bad_magic: - return "Invalid profile data (bad magic)"; + return "Invalid instrumented profile data (bad magic)"; case instrprof_error::bad_header: - return "Invalid profile data (file header is corrupt)"; + return "Invalid instrumented profile data (file header is corrupt)"; case instrprof_error::unsupported_version: - return "Unsupported profiling format version"; + return "Unsupported instrumented profile format version"; case instrprof_error::unsupported_hash_type: - return "Unsupported profiling hash"; + return "Unsupported instrumented profile hash type"; case instrprof_error::too_large: return "Too much profile data"; case instrprof_error::truncated: return "Truncated profile data"; case instrprof_error::malformed: - return "Malformed profile data"; + return "Malformed instrumented profile data"; case instrprof_error::unknown_function: return "No profile data available for function"; case instrprof_error::hash_mismatch: Index: lib/ProfileData/InstrProfReader.cpp =================================================================== --- lib/ProfileData/InstrProfReader.cpp +++ lib/ProfileData/InstrProfReader.cpp @@ -54,8 +54,10 @@ Result.reset(new RawInstrProfReader64(std::move(Buffer))); else if (RawInstrProfReader32::hasFormat(*Buffer)) Result.reset(new RawInstrProfReader32(std::move(Buffer))); - else + else if (TextInstrProfReader::hasFormat(*Buffer)) Result.reset(new TextInstrProfReader(std::move(Buffer))); + else + return instrprof_error::malformed; // Initialize the reader and return the result. if (std::error_code EC = initializeReader(*Result)) @@ -97,6 +99,15 @@ *this = InstrProfIterator(); } +bool TextInstrProfReader::hasFormat(const MemoryBuffer &Buffer) { + // Verify that this really looks like plain ASCII text by checking a + // 'reasonable' number of characters (up to profile magic size). + size_t count = std::min(Buffer.getBufferSize(), sizeof(uint64_t)); + StringRef buffer = Buffer.getBufferStart(); + return count == 0 || std::all_of(buffer.begin(), buffer.begin() + count, + [](char c) { return ::isprint(c) || ::isspace(c); }); +} + std::error_code TextInstrProfReader::readNextRecord(InstrProfRecord &Record) { // Skip empty lines and comments. while (!Line.is_at_end() && (Line->empty() || Line->startswith("#"))) Index: lib/ProfileData/SampleProf.cpp =================================================================== --- lib/ProfileData/SampleProf.cpp +++ lib/ProfileData/SampleProf.cpp @@ -27,17 +27,17 @@ case sampleprof_error::success: return "Success"; case sampleprof_error::bad_magic: - return "Invalid file format (bad magic)"; + return "Invalid sampled profile data (bad magic)"; case sampleprof_error::unsupported_version: - return "Unsupported format version"; + return "Unsupported sampled profile format version"; case sampleprof_error::too_large: return "Too much profile data"; case sampleprof_error::truncated: return "Truncated profile data"; case sampleprof_error::malformed: - return "Malformed profile data"; + return "Malformed sampled profile data"; case sampleprof_error::unrecognized_format: - return "Unrecognized profile encoding format"; + return "Unrecognized sampled profile encoding format"; case sampleprof_error::unsupported_writing_format: return "Profile encoding format unsupported for writing operations"; case sampleprof_error::truncated_name_table: Index: lib/ProfileData/SampleProfReader.cpp =================================================================== --- lib/ProfileData/SampleProfReader.cpp +++ lib/ProfileData/SampleProfReader.cpp @@ -253,6 +253,15 @@ return sampleprof_error::success; } +bool SampleProfileReaderText::hasFormat(const MemoryBuffer &Buffer) { + // Verify that this really looks like plain ASCII text by checking a + // 'reasonable' number of characters (up to profile magic size). + size_t count = std::min(Buffer.getBufferSize(), sizeof(uint64_t)); + StringRef buffer = Buffer.getBufferStart(); + return count == 0 || std::all_of(buffer.begin(), buffer.begin() + count, + [](char c) { return ::isprint(c) || ::isspace(c); }); +} + template ErrorOr SampleProfileReaderBinary::readNumber() { unsigned NumBytesRead = 0; std::error_code EC; @@ -716,8 +725,10 @@ Reader.reset(new SampleProfileReaderBinary(std::move(Buffer), C)); else if (SampleProfileReaderGCC::hasFormat(*Buffer)) Reader.reset(new SampleProfileReaderGCC(std::move(Buffer), C)); - else + else if (SampleProfileReaderText::hasFormat(*Buffer)) Reader.reset(new SampleProfileReaderText(std::move(Buffer), C)); + else + return sampleprof_error::malformed; if (std::error_code EC = Reader->readHeader()) return EC; Index: test/tools/llvm-profdata/raw-magic-but-no-header.test =================================================================== --- test/tools/llvm-profdata/raw-magic-but-no-header.test +++ test/tools/llvm-profdata/raw-magic-but-no-header.test @@ -3,4 +3,4 @@ RUN: printf '\377lprofr\201' > %t RUN: not llvm-profdata show %t 2>&1 | FileCheck %s -CHECK: error: {{.+}}: Invalid profile data (file header is corrupt) +CHECK: error: {{.+}}: Invalid instrumented profile data (file header is corrupt) Index: test/tools/llvm-profdata/text-format-errors.test =================================================================== --- test/tools/llvm-profdata/text-format-errors.test +++ test/tools/llvm-profdata/text-format-errors.test @@ -1,10 +1,10 @@ RUN: not llvm-profdata show %p/Inputs/invalid-count-later.proftext 2>&1 | FileCheck %s --check-prefix=INVALID-COUNT-LATER RUN: not llvm-profdata merge %p/Inputs/invalid-count-later.proftext %p/Inputs/invalid-count-later.profdata -o %t.out 2>&1 | FileCheck %s --check-prefix=INVALID-COUNT-LATER -INVALID-COUNT-LATER: error: {{.*}}invalid-count-later.proftext: Malformed profile data +INVALID-COUNT-LATER: error: {{.*}}invalid-count-later.proftext: Malformed {{instrumented|sampled}} profile data RUN: not llvm-profdata show %p/Inputs/bad-hash.proftext 2>&1 | FileCheck %s --check-prefix=BAD-HASH RUN: not llvm-profdata merge %p/Inputs/bad-hash.proftext %p/Inputs/bad-hash.proftext -o %t.out 2>&1 | FileCheck %s --check-prefix=BAD-HASH -BAD-HASH: error: {{.*}}bad-hash.proftext: Malformed profile data +BAD-HASH: error: {{.*}}bad-hash.proftext: Malformed {{instrumented|sampled}} profile data RUN: not llvm-profdata show %p/Inputs/no-counts.proftext 2>&1 | FileCheck %s --check-prefix=NO-COUNTS -NO-COUNTS: error: {{.*}}no-counts.proftext: Malformed profile data +NO-COUNTS: error: {{.*}}no-counts.proftext: Malformed {{instrumented|sampled}} profile data