From 923a3cc160a14e61bd2847f9b011bb4d6ce4fc71 Mon Sep 17 00:00:00 2001 From: Parth Date: Sun, 6 Jul 2025 22:52:50 +0530 Subject: [PATCH] [LLD] Fix crash on parsing ':ALIGN' in linker script (#146723) The linker was crashing due to stack overflow when parsing ':ALIGN' in an output section description. This commit fixes the linker script parser so that the crash does not happen. The root cause of the stack overflow is how we parse expressions (readExpr) in linker script and the behavior of ScriptLexer::expect(...) utility. ScriptLexer::expect does not do anything if errors have already been encountered during linker script parsing. In particular, it never increments the current token position in the script file, even if the current token is the same as the expected token. This causes an infinite call cycle on parsing an expression such as '(4096)' when an error has already been encountered. readExpr() calls readPrimary() readPrimary() calls readParenExpr() readParenExpr(): expect("("); // no-op, current token still points to '(' Expression *E = readExpr(); // The cycle continues... Closes #146722 Signed-off-by: Parth Arora --- lld/ELF/ScriptParser.cpp | 2 ++ lld/test/ELF/linkerscript/align-section.test | 21 ++++++++++++++++++-- 2 files changed, 21 insertions(+), 2 deletions(-) diff --git a/lld/ELF/ScriptParser.cpp b/lld/ELF/ScriptParser.cpp index 593d5636f245..ddfa24d9cacf 100644 --- a/lld/ELF/ScriptParser.cpp +++ b/lld/ELF/ScriptParser.cpp @@ -1229,6 +1229,8 @@ SymbolAssignment *ScriptParser::readSymbolAssignment(StringRef name) { // This is an operator-precedence parser to parse a linker // script expression. Expr ScriptParser::readExpr() { + if (atEOF()) + return []() { return 0; }; // Our lexer is context-aware. Set the in-expression bit so that // they apply different tokenization rules. SaveAndRestore saved(lexState, State::Expr); diff --git a/lld/test/ELF/linkerscript/align-section.test b/lld/test/ELF/linkerscript/align-section.test index 7a28fef2076e..1324be24a932 100644 --- a/lld/test/ELF/linkerscript/align-section.test +++ b/lld/test/ELF/linkerscript/align-section.test @@ -1,7 +1,24 @@ # REQUIRES: x86 -# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux /dev/null -o %t.o -# RUN: ld.lld -o %t --script %s %t.o -shared +# RUN: rm -rf %t && split-file %s %t && cd %t + +# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux /dev/null -o a.o +# RUN: ld.lld --script a.t a.o -shared # lld shouldn't crash. +#--- a.t SECTIONS { .foo : ALIGN(2M) {} } + +# RUN: not ld.lld --script b.t 2>&1 | FileCheck %s --match-full-lines --strict-whitespace + +# lld should not crash and report the error properly. + +# CHECK:{{.*}} error: b.t:3: malformed number: : +# CHECK:>>> S :ALIGN(4096) {} +# CHECK:>>> ^ + +#--- b.t +SECTIONS +{ + S :ALIGN(4096) {} +}