[llvm] [Profile] Add a more descriptive message to the bad_header error (PR #211281)
Wael Yehia via llvm-commits
llvm-commits at lists.llvm.org
Wed Jul 22 07:55:55 PDT 2026
https://github.com/w2yehia created https://github.com/llvm/llvm-project/pull/211281
At the moment, the raw profile reader diagnoses different problem with the same error message "invalid instrumentation profile data (file header is corrupt)". On AIX, we had users report such problems thinking it's a compiler bug, while the real problem was truncated profiles.
The particular case they hit was the condition [here](https://github.com/llvm/llvm-project/blob/668803fa73bdf2f8d095162a1f81c000d18458c9/llvm/lib/ProfileData/InstrProfReader.cpp#L652):
```
Error RawInstrProfReader<IntPtrT>::readHeader(...) {
...
if (Start + ValueDataOffset > DataBuffer->getBufferEnd())
return error(instrprof_error::bad_header);
```
This could indicate a corrupted header (large garbage values for some sections) or a truncated file.
I figured if we print the values and sizes we read in the header, it will give the user more info.
This PR
1. adds an extra description for a couple of `bad_header` error points, and
2. updates `tools/llvm-profdata/insufficient-binary-ids-size.test`: this test was originally meant to test a truncated BinaryId section, but the test hasn't been updated to reflect new profile header changes and now is failing due to a truncated header. But both errors are reported as `bad_header`, which is probably why it was uncaught by authors that updated the profile header.
>From a58abcd3ae8aa70335dde616bbaf6d35f54ddead Mon Sep 17 00:00:00 2001
From: Wael Yehia <wyehia at ca.ibm.com>
Date: Wed, 22 Jul 2026 03:43:48 +0000
Subject: [PATCH] [Profile] Add a more descriptive message to the bad_header
error
---
llvm/lib/ProfileData/InstrProfReader.cpp | 33 ++++++++++++--
.../insufficient-binary-ids-size.test | 20 ++++++---
.../misaligned-binary-ids-size.test | 2 +-
.../raw-magic-but-no-header.test | 2 +-
.../llvm-profdata/truncated-profile.test | 44 +++++++++++++++++++
5 files changed, 90 insertions(+), 11 deletions(-)
create mode 100644 llvm/test/tools/llvm-profdata/truncated-profile.test
diff --git a/llvm/lib/ProfileData/InstrProfReader.cpp b/llvm/lib/ProfileData/InstrProfReader.cpp
index 05770f83ed160..444ac90768d48 100644
--- a/llvm/lib/ProfileData/InstrProfReader.cpp
+++ b/llvm/lib/ProfileData/InstrProfReader.cpp
@@ -513,7 +513,8 @@ Error RawInstrProfReader<IntPtrT>::readHeader() {
if (!hasFormat(*DataBuffer))
return error(instrprof_error::bad_magic);
if (DataBuffer->getBufferSize() < sizeof(RawInstrProf::Header))
- return error(instrprof_error::bad_header);
+ return error(instrprof_error::bad_header,
+ std::string("Profile file header is truncated"));
auto *Header = reinterpret_cast<const RawInstrProf::Header *>(
DataBuffer->getBufferStart());
ShouldSwapBytes = Header->Magic != RawInstrProf::getMagic<IntPtrT>();
@@ -597,7 +598,10 @@ Error RawInstrProfReader<IntPtrT>::readHeader(
const uint8_t *BinaryIdEnd = BinaryIdStart + BinaryIdSize;
const uint8_t *BufferEnd = (const uint8_t *)DataBuffer->getBufferEnd();
if (BinaryIdSize % sizeof(uint64_t) || BinaryIdEnd > BufferEnd)
- return error(instrprof_error::bad_header);
+ return error(instrprof_error::bad_header,
+ ("BinaryIdSize (" + Twine(BinaryIdSize) +
+ ") is not a multiple of 8 or the profile is truncated")
+ .str());
ArrayRef<uint8_t> BinaryIdsBuffer(BinaryIdStart, BinaryIdSize);
if (!BinaryIdsBuffer.empty()) {
if (Error Err = readBinaryIdsInternal(*DataBuffer, BinaryIdsBuffer,
@@ -650,7 +654,25 @@ Error RawInstrProfReader<IntPtrT>::readHeader(
auto *Start = reinterpret_cast<const char *>(&Header);
if (Start + ValueDataOffset > DataBuffer->getBufferEnd())
- return error(instrprof_error::bad_header);
+ return error(
+ instrprof_error::bad_header,
+ ("Profile file size (" + Twine(DataBuffer->getBufferSize()) +
+ " bytes) smaller than expected (at least " + Twine(ValueDataOffset) +
+ " bytes = " +
+ Twine(BinaryIdSize) + "(BinaryIdSize) + " +
+ Twine(DataSize) + "(DataSize) + " +
+ Twine(CountersSize) + "(CountersSize) + " +
+ Twine(NumBitmapBytes) + "(NumBitmapBytes) + " +
+ Twine(UniformCountersSectionSize) + "(UniformCountersSectionSize) + " +
+ Twine(NamesSize) + "(NamesSize) + " +
+ Twine(VTableSectionSize) + "(VTableSectionSize) + " +
+ Twine(VTableNameSize) + "(VTableNameSize) + " +
+ Twine(DataOffset - BinaryIdSize + PaddingBytesBeforeCounters +
+ PaddingBytesAfterCounters + PaddingBytesAfterBitmapBytes +
+ PaddingBytesAfterUniformCounters + PaddingBytesAfterNames +
+ PaddingBytesAfterVTableProfData + PaddingBytesAfterVTableNames) +
+ "(Padding))")
+ .str());
if (BIDFetcher) {
std::vector<object::BuildID> BinaryIDs;
@@ -1373,7 +1395,10 @@ Error IndexedInstrProfReader::readHeader() {
uint64_t BinaryIdsSize =
support::endian::readNext<uint64_t, llvm::endianness::little>(Ptr);
if (BinaryIdsSize % sizeof(uint64_t))
- return error(instrprof_error::bad_header);
+ return error(instrprof_error::bad_header,
+ ("BinaryIdSize (" + Twine(BinaryIdsSize) +
+ ") is not a multiple of 8")
+ .str());
// Set the binary ids start.
BinaryIdsBuffer = ArrayRef<uint8_t>(Ptr, BinaryIdsSize);
if (Ptr > (const unsigned char *)DataBuffer->getBufferEnd())
diff --git a/llvm/test/tools/llvm-profdata/insufficient-binary-ids-size.test b/llvm/test/tools/llvm-profdata/insufficient-binary-ids-size.test
index 66fba4ba495b7..b2ee0d9246735 100644
--- a/llvm/test/tools/llvm-profdata/insufficient-binary-ids-size.test
+++ b/llvm/test/tools/llvm-profdata/insufficient-binary-ids-size.test
@@ -3,12 +3,13 @@
// TODO: use a builtin version of printf
UNSUPPORTED: system-zos
RUN: printf '\201rforpl\377' > %t.profraw
-RUN: printf '\10\0\0\0\0\0\0\0' >> %t.profraw
+RUN: printf '\x0B\0\0\0\0\0\0\0' >> %t.profraw
// We should fail on this because the data buffer (profraw file) is not long
// enough to hold this binary IDs size. NOTE that this (combined with the 8-byte
// alignment requirement for binary IDs size) will ensure we can at least read one
// 8-byte size if the binary IDs are provided.
-RUN: printf '\8\0\0\0\0\0\0\0' >> %t.profraw
+// BinaryIdSize - set to 8 bytes
+RUN: printf '\x08\0\0\0\0\0\0\0' >> %t.profraw
RUN: printf '\0\0\0\0\0\0\0\0' >> %t.profraw
RUN: printf '\0\0\0\0\0\0\0\0' >> %t.profraw
RUN: printf '\0\0\0\0\0\0\0\0' >> %t.profraw
@@ -17,8 +18,17 @@ RUN: printf '\0\0\0\0\0\0\0\0' >> %t.profraw
RUN: printf '\0\0\0\0\0\0\0\0' >> %t.profraw
RUN: printf '\0\0\0\0\0\0\0\0' >> %t.profraw
RUN: printf '\0\0\0\0\0\0\0\0' >> %t.profraw
-
+RUN: printf '\0\0\0\0\0\0\0\0' >> %t.profraw
+RUN: printf '\0\0\0\0\0\0\0\0' >> %t.profraw
+RUN: printf '\0\0\0\0\0\0\0\0' >> %t.profraw
+RUN: printf '\0\0\0\0\0\0\0\0' >> %t.profraw
+RUN: printf '\0\0\0\0\0\0\0\0' >> %t.profraw
+RUN: printf '\0\0\0\0\0\0\0\0' >> %t.profraw
+RUN: printf '\0\0\0\0\0\0\0\0' >> %t.profraw
+RUN: printf '\0\0\0\0\0\0\0\0' >> %t.profraw
+// ^^ end of Profile Header ^^
+// Incomplete binary IDs data - only 7 bytes instead of 8
RUN: printf '\0\0\0\0\0\0\0' >> %t.profraw
-// RUN: not llvm-profdata show --binary-ids %t.profraw 2>&1 | FileCheck %s
-// CHECK: invalid instrumentation profile data (file header is corrupt)
+RUN: not llvm-profdata show --binary-ids %t.profraw 2>&1 | FileCheck %s
+CHECK: invalid instrumentation profile data (file header is corrupt): BinaryIdSize (8) is not a multiple of 8 or the profile is truncated
diff --git a/llvm/test/tools/llvm-profdata/misaligned-binary-ids-size.test b/llvm/test/tools/llvm-profdata/misaligned-binary-ids-size.test
index 46be16d8b728b..4214b15575560 100644
--- a/llvm/test/tools/llvm-profdata/misaligned-binary-ids-size.test
+++ b/llvm/test/tools/llvm-profdata/misaligned-binary-ids-size.test
@@ -30,4 +30,4 @@ RUN: printf '\2\2\2\2\2\2\2\2' >> %t.profraw
RUN: printf '\3\3\3\3\0\0\0\0' >> %t.profraw
// RUN: not llvm-profdata show --binary-ids %t.profraw 2>&1 | FileCheck %s
-// CHECK: invalid instrumentation profile data (file header is corrupt)
+// CHECK: invalid instrumentation profile data (file header is corrupt): BinaryIdSize (63) is not a multiple of 8 or the profile is truncated
diff --git a/llvm/test/tools/llvm-profdata/raw-magic-but-no-header.test b/llvm/test/tools/llvm-profdata/raw-magic-but-no-header.test
index caec1663a04fd..31e1588eedcff 100644
--- a/llvm/test/tools/llvm-profdata/raw-magic-but-no-header.test
+++ b/llvm/test/tools/llvm-profdata/raw-magic-but-no-header.test
@@ -7,4 +7,4 @@ RUN: not llvm-profdata show %t 2>&1 | FileCheck %s
RUN: printf '\377lprofr\201' > %t
RUN: not llvm-profdata show %t 2>&1 | FileCheck %s
-CHECK: error: {{.+}}: invalid instrumentation profile data (file header is corrupt)
+CHECK: error: {{.+}}: invalid instrumentation profile data (file header is corrupt): Profile file header is truncated
diff --git a/llvm/test/tools/llvm-profdata/truncated-profile.test b/llvm/test/tools/llvm-profdata/truncated-profile.test
new file mode 100644
index 0000000000000..fc51a21b217c3
--- /dev/null
+++ b/llvm/test/tools/llvm-profdata/truncated-profile.test
@@ -0,0 +1,44 @@
+// Magic
+RUN: printf '\x81rforpl\xff' > %t.profraw
+// Version (11 = 0x0B)
+RUN: printf '\13\0\0\0\0\0\0\0' >> %t.profraw
+// BinaryIdsSize
+RUN: printf '\0\0\0\0\0\0\0\0' >> %t.profraw
+// NumData
+RUN: printf '\1\0\0\0\0\0\0\0' >> %t.profraw
+// PaddingBytesBeforeCounters
+RUN: printf '\0\0\0\0\0\0\0\0' >> %t.profraw
+// NumCounters
+RUN: printf '\1\0\0\0\0\0\0\0' >> %t.profraw
+// PaddingBytesAfterCounters
+RUN: printf '\0\0\0\0\0\0\0\0' >> %t.profraw
+// NumBitmapBytes
+RUN: printf '\0\0\0\0\0\0\0\0' >> %t.profraw
+// PaddingBytesAfterBitmapBytes
+RUN: printf '\0\0\0\0\0\0\0\0' >> %t.profraw
+// NumUniformCounters
+RUN: printf '\0\0\0\0\0\0\0\0' >> %t.profraw
+// PaddingBytesAfterUniformCounters
+RUN: printf '\0\0\0\0\0\0\0\0' >> %t.profraw
+// UniformCountersDelta
+RUN: printf '\0\0\0\0\0\0\0\0' >> %t.profraw
+// NamesSize
+RUN: printf '\x10\0\0\0\0\0\0\0' >> %t.profraw
+// CountersDelta
+RUN: printf '\xF8\xFF\xFF\xFF\0\0\0\0' >> %t.profraw
+// BitmapDelta
+RUN: printf '\0\0\0\0\0\0\0\0' >> %t.profraw
+// NamesDelta
+RUN: printf '\x58\x87\x00\x10\0\0\0\0' >> %t.profraw
+// NumVTables
+RUN: printf '\0\0\0\0\0\0\0\0' >> %t.profraw
+// VNamesSize
+RUN: printf '\0\0\0\0\0\0\0\0' >> %t.profraw
+// ValueKindLast
+RUN: printf '\3\0\0\0\0\0\0\0' >> %t.profraw
+// No Binary Ids
+// Array of __llvm_prof_data goes next but we'll truncate it to 4 bytes
+RUN: printf '\0\0\0\0' >> %t.profraw
+
+RUN: not llvm-profdata show %t.profraw 2>&1 | FileCheck %s
+CHECK: invalid instrumentation profile data (file header is corrupt): Profile file size (156 bytes) smaller than expected (at least 248 bytes = 0(BinaryIdSize) + 72(DataSize) + 8(CountersSize) + 0(NumBitmapBytes) + 0(UniformCountersSectionSize) + 16(NamesSize) + 0(VTableSectionSize) + 0(VTableNameSize) + 152(Padding))
More information about the llvm-commits
mailing list