[lld] [ELF] Fix crash when INCLUDE'd linker script ends mid-assignment (PR #192198)

via llvm-commits llvm-commits at lists.llvm.org
Wed Apr 15 00:07:18 PDT 2026


llvmbot wrote:


<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-lld-elf

@llvm/pr-subscribers-lld

Author: Fangrui Song (MaskRay)

<details>
<summary>Changes</summary>

`readAssignment` builds `commandString` from a `[oldS, curTok)` byte
span. If the expression is read from an INCLUDE'd script whose buffer is
exhausted before the terminator, the two pointers come from different
`MemoryBuffer`s, leading to `std::length_error`.

Fix #<!-- -->190376: Skip the map-file string if the
buffer changed.


---
Full diff: https://github.com/llvm/llvm-project/pull/192198.diff


2 Files Affected:

- (modified) lld/ELF/ScriptParser.cpp (+8-2) 
- (added) lld/test/ELF/linkerscript/include-mid-assignment.s (+31) 


``````````diff
diff --git a/lld/ELF/ScriptParser.cpp b/lld/ELF/ScriptParser.cpp
index 0300b956e6071..c52982d525237 100644
--- a/lld/ELF/ScriptParser.cpp
+++ b/lld/ELF/ScriptParser.cpp
@@ -1157,6 +1157,7 @@ SymbolAssignment *ScriptParser::readAssignment(StringRef tok) {
     return make<SymbolAssignment>(".", readAssert(), 0, getCurrentLocation());
 
   const char *oldS = prevTok.data();
+  const char *oldBufBegin = curBuf.begin;
   SymbolAssignment *cmd = nullptr;
   bool savedSeenRelroEnd = ctx.script->seenRelroEnd;
   const StringRef op = peek();
@@ -1179,8 +1180,13 @@ SymbolAssignment *ScriptParser::readAssignment(StringRef tok) {
 
   if (cmd) {
     cmd->dataSegmentRelroEnd = !savedSeenRelroEnd && ctx.script->seenRelroEnd;
-    cmd->commandString = StringRef(oldS, curTok.data() - oldS).str();
-    squeezeSpaces(cmd->commandString);
+    // If the inner buffer of an INCLUDE was exhausted while reading the
+    // expression, oldS lives in a popped buffer and the [oldS, curTok) span is
+    // not a valid pointer range.
+    if (curBuf.begin == oldBufBegin) {
+      cmd->commandString = StringRef(oldS, curTok.data() - oldS).str();
+      squeezeSpaces(cmd->commandString);
+    }
     expect(";");
   }
   return cmd;
diff --git a/lld/test/ELF/linkerscript/include-mid-assignment.s b/lld/test/ELF/linkerscript/include-mid-assignment.s
new file mode 100644
index 0000000000000..783e795bb4c77
--- /dev/null
+++ b/lld/test/ELF/linkerscript/include-mid-assignment.s
@@ -0,0 +1,31 @@
+# REQUIRES: x86
+## When recording `commandString`, an assignment in an INCLUDEd linker script
+## that is missing the trailing ';' must not crash lld. Same for a PROVIDE
+## whose inner buffer is exhausted before the closing ')'.
+
+# RUN: rm -rf %t && split-file %s %t && cd %t
+# RUN: llvm-mc -filetype=obj -triple=x86_64 a.s -o a.o
+# RUN: not ld.lld a.o -T outer.lds 2>&1 | FileCheck %s
+# RUN: not ld.lld a.o -T outer2.lds 2>&1 | FileCheck %s --check-prefix=CHECK2
+
+# CHECK: error: outer.lds:2: ; expected, but got {{.*}}
+# CHECK2: error: outer2.lds:2: ) expected, but got {{.*}}
+
+#--- outer.lds
+INCLUDE "inc.lds"
+SECTIONS { .text : { *(.text*) } }
+
+#--- inc.lds
+foo = 1
+
+#--- outer2.lds
+INCLUDE "inc2.lds"
+SECTIONS { .text : { *(.text*) } }
+
+#--- inc2.lds
+PROVIDE(bar = 1
+
+#--- a.s
+.globl _start
+_start:
+  ret

``````````

</details>


https://github.com/llvm/llvm-project/pull/192198


More information about the llvm-commits mailing list