[Lldb-commits] [lldb] [lldb][NativePDB] don't assert when a public symbol sits past its section (PR #225734)
Charles Zablit via lldb-commits
lldb-commits at lists.llvm.org
Wed Sep 23 04:47:27 PDT 2026
https://github.com/charles-zablit updated https://github.com/llvm/llvm-project/pull/225734
>From 1626fa81d14755aa11ef63b9dbf128616bb0e268 Mon Sep 17 00:00:00 2001
From: Charles Zablit <c_zablit at apple.com>
Date: Wed, 23 Sep 2026 12:44:10 +0100
Subject: [PATCH 1/2] [lldb][NativePDB] don't assert when a public symbol sits
past its section
---
.../NativePDB/SymbolFileNativePDB.cpp | 19 ++++++++++--
.../NativePDB/Inputs/corrupt-public-offset.py | 31 +++++++++++++++++++
.../public-symbol-offset-past-section-end.cpp | 23 ++++++++++++++
3 files changed, 70 insertions(+), 3 deletions(-)
create mode 100644 lldb/test/Shell/SymbolFile/NativePDB/Inputs/corrupt-public-offset.py
create mode 100644 lldb/test/Shell/SymbolFile/NativePDB/public-symbol-offset-past-section-end.cpp
diff --git a/lldb/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.cpp b/lldb/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.cpp
index aa16ab713527df..33547f8fa06114 100644
--- a/lldb/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.cpp
+++ b/lldb/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.cpp
@@ -1290,12 +1290,25 @@ void SymbolFileNativePDB::AddSymbols(Symtab &symtab) {
return;
if (next && last_sym.Segment == next->Segment) {
- assert(last_sym.Offset <= next->Offset);
+ if (next->Offset < last_sym.Offset) {
+ LLDB_LOG(GetLog(LLDBLog::Symbols),
+ "Ignoring size estimate for '{0}': segment {1} offset {2} is "
+ "greater than the following offset {3}",
+ last_sym.Name, last_sym.Segment, last_sym.Offset,
+ next->Offset);
+ return;
+ }
last->SetByteSize(next->Offset - last_sym.Offset);
} else {
// the last symbol was the last in its section
- assert(section_sp->GetByteSize() >= last_sym.Offset);
- assert(!next || next->Segment > last_sym.Segment);
+ if (section_sp->GetByteSize() < last_sym.Offset) {
+ LLDB_LOG(GetLog(LLDBLog::Symbols),
+ "Ignoring size estimate for '{0}': segment {1} offset {2} is "
+ "past the end of section '{3}' (size {4})",
+ last_sym.Name, last_sym.Segment, last_sym.Offset,
+ section_sp->GetName(), section_sp->GetByteSize());
+ return;
+ }
last->SetByteSize(section_sp->GetByteSize() - last_sym.Offset);
}
};
diff --git a/lldb/test/Shell/SymbolFile/NativePDB/Inputs/corrupt-public-offset.py b/lldb/test/Shell/SymbolFile/NativePDB/Inputs/corrupt-public-offset.py
new file mode 100644
index 00000000000000..364c4dc59c952d
--- /dev/null
+++ b/lldb/test/Shell/SymbolFile/NativePDB/Inputs/corrupt-public-offset.py
@@ -0,0 +1,31 @@
+#!/usr/bin/env python3
+"""Rewrite the Offset of a S_PUB32 record in a llvm-pdbutil pdb2yaml dump.
+
+Used to simulate a PDB whose public symbol records disagree with the
+executable's section table (as can happen with real-world PDBs).
+"""
+import re
+import sys
+
+if len(sys.argv) != 4:
+ sys.exit(
+ "usage: corrupt-public-offset.py <yaml-file> <symbol-name> <new-offset>"
+ )
+
+yaml_path, symbol_name, new_offset = sys.argv[1:4]
+new_offset = int(new_offset, 0)
+
+with open(yaml_path) as f:
+ text = f.read()
+
+pattern = re.compile(
+ r"(Offset:\s+)\d+(\s*\n\s*Segment:\s+\d+\s*\n\s*Name:\s+"
+ + re.escape(symbol_name)
+ + r"\b\s*\n)"
+)
+text, count = pattern.subn(r"\g<1>" + str(new_offset) + r"\g<2>", text, count=1)
+if count != 1:
+ sys.exit(f"could not find a S_PUB32 record named '{symbol_name}' in {yaml_path}")
+
+with open(yaml_path, "w") as f:
+ f.write(text)
diff --git a/lldb/test/Shell/SymbolFile/NativePDB/public-symbol-offset-past-section-end.cpp b/lldb/test/Shell/SymbolFile/NativePDB/public-symbol-offset-past-section-end.cpp
new file mode 100644
index 00000000000000..f10a4935ec9a5f
--- /dev/null
+++ b/lldb/test/Shell/SymbolFile/NativePDB/public-symbol-offset-past-section-end.cpp
@@ -0,0 +1,23 @@
+// REQUIRES: lld, x86
+
+// A public symbol's offset is not guaranteed to agree with
+// the size of the section its segment maps to (this can happen with
+// real-world PDBs, e.g. after incremental linking).
+//
+// RUN: %build --compiler=clang-cl --arch=64 --nodefaultlib -o %t.exe -- %s
+// RUN: llvm-pdbutil pdb2yaml --all %t.pdb > %t.yaml
+// RUN: %python %S/Inputs/corrupt-public-offset.py %t.yaml main 0x0fffffff
+// RUN: llvm-pdbutil yaml2pdb %t.yaml -pdb=%t.pdb
+// RUN: env LLDB_USE_NATIVE_PDB_READER=1 lldb-test symtab %t.exe \
+// RUN: --find-symbols-by-regex=".*" | FileCheck %s
+
+int global_one = 1;
+int global_two = 2;
+
+int main() { return global_one + global_two; }
+
+// `main`'s offset was rewritten to a value past the end of its section, so
+// its size estimate must be left at 0 rather than underflowing.
+// CHECK-DAG: Code{{.*}}0x0000000000000000 0x00000000 main
+// CHECK-DAG: Data{{.*}}global_one
+// CHECK-DAG: Data{{.*}}global_two
>From b3b66fc866966c359a7f518da2b1c4ed197770fe Mon Sep 17 00:00:00 2001
From: Charles Zablit <c_zablit at apple.com>
Date: Wed, 23 Sep 2026 12:47:12 +0100
Subject: [PATCH 2/2] fix python formatting
---
.../SymbolFile/NativePDB/Inputs/corrupt-public-offset.py | 5 ++---
1 file changed, 2 insertions(+), 3 deletions(-)
diff --git a/lldb/test/Shell/SymbolFile/NativePDB/Inputs/corrupt-public-offset.py b/lldb/test/Shell/SymbolFile/NativePDB/Inputs/corrupt-public-offset.py
index 364c4dc59c952d..7d650c39c6f062 100644
--- a/lldb/test/Shell/SymbolFile/NativePDB/Inputs/corrupt-public-offset.py
+++ b/lldb/test/Shell/SymbolFile/NativePDB/Inputs/corrupt-public-offset.py
@@ -4,13 +4,12 @@
Used to simulate a PDB whose public symbol records disagree with the
executable's section table (as can happen with real-world PDBs).
"""
+
import re
import sys
if len(sys.argv) != 4:
- sys.exit(
- "usage: corrupt-public-offset.py <yaml-file> <symbol-name> <new-offset>"
- )
+ sys.exit("usage: corrupt-public-offset.py <yaml-file> <symbol-name> <new-offset>")
yaml_path, symbol_name, new_offset = sys.argv[1:4]
new_offset = int(new_offset, 0)
More information about the lldb-commits
mailing list