[llvm] [DebugInfo][DWARF] Bounds-check the unit-index parallel table (PR #213285)
Matt Davis via llvm-commits
llvm-commits at lists.llvm.org
Mon Aug 3 06:38:26 PDT 2026
https://github.com/enferex updated https://github.com/llvm/llvm-project/pull/213285
>From 4ac0b3fde9af49c1b88cfc90151db3f35760828b Mon Sep 17 00:00:00 2001
From: Matt Davis <mattd at nvidia.com>
Date: Thu, 30 Jul 2026 19:50:54 +0000
Subject: [PATCH 1/3] [DebugInfo][DWARF] Bounds-check the unit-index parallel
table
DWARFUnitIndex::parseImpl() sizes the Contribs array to Header.NumUnits, then
for each hash-table row reads a 32-bit Index from the .debug_{cu,tu}_index
section and writes Contribs[Index - 1]. Index == 0 is skipped, but there was no
upper bound, so a crafted index with Index > NumUnits writes a heap pointer one
or more slots past the array. Reject Index > NumUnits before the write.
Reachable from any consumer of a DWP package (llvm-dwarfdump, llvm-dwp, lldb,
llvm-symbolizer).
Co-Authored-By: Claude Opus 4.8 <noreply at anthropic.com>
---
llvm/lib/DebugInfo/DWARF/DWARFUnitIndex.cpp | 2 ++
1 file changed, 2 insertions(+)
diff --git a/llvm/lib/DebugInfo/DWARF/DWARFUnitIndex.cpp b/llvm/lib/DebugInfo/DWARF/DWARFUnitIndex.cpp
index 08abcf13d0618..f5d7b1e19dd11 100644
--- a/llvm/lib/DebugInfo/DWARF/DWARFUnitIndex.cpp
+++ b/llvm/lib/DebugInfo/DWARF/DWARFUnitIndex.cpp
@@ -159,6 +159,8 @@ bool DWARFUnitIndex::parseImpl(DataExtractor IndexData) {
auto Index = IndexData.getU32(&Offset);
if (!Index)
continue;
+ if (Index > Header.NumUnits)
+ return false;
Rows[i].Index = this;
Rows[i].Contributions =
std::make_unique<Entry::SectionContribution[]>(Header.NumColumns);
>From da5c6ac566803ec1b35141ec821bb5e188e8ff13 Mon Sep 17 00:00:00 2001
From: Matt Davis <mattd at nvidia.com>
Date: Thu, 30 Jul 2026 19:50:55 +0000
Subject: [PATCH 2/3] [DebugInfo][DWARF] Add unit test for unit-index
parallel-table bounds check
Feed a crafted .debug_cu_index whose parallel-table row index exceeds NumUnits
and check that DWARFUnitIndex::parse() returns false instead of writing a heap
pointer out of bounds.
Co-Authored-By: Claude Opus 4.8 <noreply at anthropic.com>
---
llvm/unittests/DebugInfo/DWARF/CMakeLists.txt | 1 +
.../DebugInfo/DWARF/DWARFUnitIndexTest.cpp | 63 +++++++++++++++++++
2 files changed, 64 insertions(+)
create mode 100644 llvm/unittests/DebugInfo/DWARF/DWARFUnitIndexTest.cpp
diff --git a/llvm/unittests/DebugInfo/DWARF/CMakeLists.txt b/llvm/unittests/DebugInfo/DWARF/CMakeLists.txt
index 167f1b310cbc6..98c4e750176cc 100644
--- a/llvm/unittests/DebugInfo/DWARF/CMakeLists.txt
+++ b/llvm/unittests/DebugInfo/DWARF/CMakeLists.txt
@@ -28,6 +28,7 @@ add_llvm_unittest(DebugInfoDWARFTests
DWARFExpressionCompactPrinterTest.cpp
DWARFFormValueTest.cpp
DWARFListTableTest.cpp
+ DWARFUnitIndexTest.cpp
DWARFLocationExpressionTest.cpp
DWARFVerifierTest.cpp
)
diff --git a/llvm/unittests/DebugInfo/DWARF/DWARFUnitIndexTest.cpp b/llvm/unittests/DebugInfo/DWARF/DWARFUnitIndexTest.cpp
new file mode 100644
index 0000000000000..b11f508dd8328
--- /dev/null
+++ b/llvm/unittests/DebugInfo/DWARF/DWARFUnitIndexTest.cpp
@@ -0,0 +1,63 @@
+//===- llvm/unittest/DebugInfo/DWARF/DWARFUnitIndexTest.cpp ---------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/DebugInfo/DWARF/DWARFUnitIndex.h"
+#include "llvm/Support/DataExtractor.h"
+#include "llvm/Support/Endian.h"
+#include "gtest/gtest.h"
+#include <cstdint>
+#include <vector>
+
+using namespace llvm;
+
+namespace {
+
+static void appendU32(std::vector<uint8_t> &B, uint32_t V) {
+ uint8_t Tmp[4];
+ support::endian::write32le(Tmp, V);
+ B.insert(B.end(), Tmp, Tmp + 4);
+}
+
+static void appendU64(std::vector<uint8_t> &B, uint64_t V) {
+ uint8_t Tmp[8];
+ support::endian::write64le(Tmp, V);
+ B.insert(B.end(), Tmp, Tmp + 8);
+}
+
+// A crafted .debug_cu_index (version 2) with one hash bucket whose parallel-
+// table Index is NumUnits + 1. Without the bounds check parseImpl() writes
+// Contribs[Index - 1], one slot past a heap array sized to NumUnits. parse()
+// must reject it and leave the index empty.
+TEST(DWARFUnitIndexTest, RejectsRowIndexBeyondNumUnits) {
+ std::vector<uint8_t> Buffer;
+ // Header: Version=2, NumColumns=1, NumUnits=1, NumBuckets=1.
+ appendU32(Buffer, 2);
+ appendU32(Buffer, 1);
+ appendU32(Buffer, 1);
+ appendU32(Buffer, 1);
+ // Hash table of signatures: NumBuckets x u64.
+ appendU64(Buffer, 0xdeadbeefULL);
+ // Parallel table of indexes: NumBuckets x u32. Index = NumUnits + 1 = 2.
+ appendU32(Buffer, 2);
+ // Column headers: NumColumns x u32 (DW_SECT_INFO serializes to 1 under v2).
+ appendU32(Buffer, 1);
+ // Table of section offsets: NumUnits*NumColumns x u32.
+ appendU32(Buffer, 0);
+ // Table of section sizes: NumUnits*NumColumns x u32.
+ appendU32(Buffer, 0);
+
+ DataExtractor Data(
+ StringRef(reinterpret_cast<const char *>(Buffer.data()), Buffer.size()),
+ /*IsLittleEndian=*/true);
+ DWARFUnitIndex Index(DW_SECT_INFO);
+ EXPECT_FALSE(Index.parse(Data));
+ // On failure parse() resets the header, so the index is falsy.
+ EXPECT_FALSE(static_cast<bool>(Index));
+}
+
+} // end anonymous namespace
>From 56dd8effb12a2bee79191ff036e96180c0602820 Mon Sep 17 00:00:00 2001
From: Matt Davis <mattd at nvidia.com>
Date: Mon, 3 Aug 2026 13:32:08 +0000
Subject: [PATCH 3/3] Remove file path from header comment.
---
llvm/unittests/DebugInfo/DWARF/DWARFUnitIndexTest.cpp | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/llvm/unittests/DebugInfo/DWARF/DWARFUnitIndexTest.cpp b/llvm/unittests/DebugInfo/DWARF/DWARFUnitIndexTest.cpp
index b11f508dd8328..fa8c8227ea4c4 100644
--- a/llvm/unittests/DebugInfo/DWARF/DWARFUnitIndexTest.cpp
+++ b/llvm/unittests/DebugInfo/DWARF/DWARFUnitIndexTest.cpp
@@ -1,4 +1,4 @@
-//===- llvm/unittest/DebugInfo/DWARF/DWARFUnitIndexTest.cpp ---------------===//
+//===----------------------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
More information about the llvm-commits
mailing list