[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