[llvm] [LFI][AArch64] Fix Segfault due to infinite recursion in LFI rewriter (PR #210267)
Sharjeel Khan via llvm-commits
llvm-commits at lists.llvm.org
Fri Jul 17 10:57:22 PDT 2026
https://github.com/Sharjeel-Khan updated https://github.com/llvm/llvm-project/pull/210267
>From 8d9eb74c530b6fd3d30832c6cdc95cda6319c3a2 Mon Sep 17 00:00:00 2001
From: Sharjeel Khan <sharjeelkhan at google.com>
Date: Thu, 16 Jul 2026 23:21:03 +0000
Subject: [PATCH 1/2] [LFI][AArch64] Fix Segfault due to infinite recursion in
LFI rewriter
When emitting a deferred LR guard, if debug info is enabled, the
emission of the guard instruction can trigger temporary labels (e.g. for
DWARF line entries). This recursively calls onLabel. Since
DeferredLRGuard was only set to false after emission, the nested call
would re-emit the guard, causing infinite recursion which leads to a
SegFault due to stack overflow. This was detected compiling
ubsan_minimal_handlers.cpp in compiler-rt. I fixed it by setting
DeferredLRGuard = false before emitting the guard.
---
.../AArch64/MCTargetDesc/AArch64MCLFIRewriter.cpp | 6 +++---
llvm/test/MC/AArch64/LFI/debug-info.s | 13 +++++++++++++
2 files changed, 16 insertions(+), 3 deletions(-)
create mode 100644 llvm/test/MC/AArch64/LFI/debug-info.s
diff --git a/llvm/lib/Target/AArch64/MCTargetDesc/AArch64MCLFIRewriter.cpp b/llvm/lib/Target/AArch64/MCTargetDesc/AArch64MCLFIRewriter.cpp
index 3c24f5ab62a61..98d82aa43eed3 100644
--- a/llvm/lib/Target/AArch64/MCTargetDesc/AArch64MCLFIRewriter.cpp
+++ b/llvm/lib/Target/AArch64/MCTargetDesc/AArch64MCLFIRewriter.cpp
@@ -301,8 +301,8 @@ void AArch64MCLFIRewriter::onLabel(const MCSymbol *, MCStreamer &Out) {
// Flush a deferred LR guard before the label, since the label is a potential
// branch target and code reached through it may use LR for control flow.
if (DeferredLRGuard && LastSTI) {
- emitAddMask(AArch64::LR, AArch64::LR, Out, *LastSTI);
DeferredLRGuard = false;
+ emitAddMask(AArch64::LR, AArch64::LR, Out, *LastSTI);
}
// Invalidate guard state since the label is a potential branch target.
@@ -312,8 +312,8 @@ void AArch64MCLFIRewriter::onLabel(const MCSymbol *, MCStreamer &Out) {
void AArch64MCLFIRewriter::finish(MCStreamer &Out) {
// Flush a deferred LR guard at the end of the stream.
if (DeferredLRGuard && LastSTI) {
- emitAddMask(AArch64::LR, AArch64::LR, Out, *LastSTI);
DeferredLRGuard = false;
+ emitAddMask(AArch64::LR, AArch64::LR, Out, *LastSTI);
}
}
@@ -948,8 +948,8 @@ void AArch64MCLFIRewriter::doRewriteInst(const MCInst &Inst, MCStreamer &Out,
// modified LR is sandboxed before it can be used to transfer control.
if (DeferredLRGuard && (isReturn(Inst) || isIndirectBranch(Inst) ||
isCall(Inst) || isBranch(Inst))) {
- emitAddMask(AArch64::LR, AArch64::LR, Out, STI);
DeferredLRGuard = false;
+ emitAddMask(AArch64::LR, AArch64::LR, Out, STI);
}
// PAC authenticated branches/calls expand to authenticate + guarded branch.
diff --git a/llvm/test/MC/AArch64/LFI/debug-info.s b/llvm/test/MC/AArch64/LFI/debug-info.s
new file mode 100644
index 0000000000000..9c6efbd79f6a2
--- /dev/null
+++ b/llvm/test/MC/AArch64/LFI/debug-info.s
@@ -0,0 +1,13 @@
+// RUN: llvm-mc -triple aarch64_lfi -filetype=obj %s -o /dev/null
+// RUN: llvm-mc -triple aarch64_lfi %s | FileCheck %s
+
+// CHECK: mov x30, x0
+// CHECK: add x30, x27, w30, uxtw
+// CHECK: next_func:
+// CHECK-NEXT: nop
+
+.file 1 "debug-info.s"
+mov x30, x0
+.loc 1 10 0
+next_func:
+ nop
>From 167678acfad92e025af0f254b18ff1c339de1057 Mon Sep 17 00:00:00 2001
From: Sharjeel Khan <sharjeelkhan at google.com>
Date: Fri, 17 Jul 2026 17:48:29 +0000
Subject: [PATCH 2/2] Use recursion guard in onLabel to prevent infinite
recursion
---
.../Target/AArch64/MCTargetDesc/AArch64MCLFIRewriter.cpp | 9 ++++++---
1 file changed, 6 insertions(+), 3 deletions(-)
diff --git a/llvm/lib/Target/AArch64/MCTargetDesc/AArch64MCLFIRewriter.cpp b/llvm/lib/Target/AArch64/MCTargetDesc/AArch64MCLFIRewriter.cpp
index 98d82aa43eed3..38e303db6b6c8 100644
--- a/llvm/lib/Target/AArch64/MCTargetDesc/AArch64MCLFIRewriter.cpp
+++ b/llvm/lib/Target/AArch64/MCTargetDesc/AArch64MCLFIRewriter.cpp
@@ -298,11 +298,14 @@ MCRegister AArch64MCLFIRewriter::mayModifyReserved(const MCInst &Inst) const {
}
void AArch64MCLFIRewriter::onLabel(const MCSymbol *, MCStreamer &Out) {
+ if (Guard)
+ return;
+
// Flush a deferred LR guard before the label, since the label is a potential
// branch target and code reached through it may use LR for control flow.
if (DeferredLRGuard && LastSTI) {
- DeferredLRGuard = false;
emitAddMask(AArch64::LR, AArch64::LR, Out, *LastSTI);
+ DeferredLRGuard = false;
}
// Invalidate guard state since the label is a potential branch target.
@@ -312,8 +315,8 @@ void AArch64MCLFIRewriter::onLabel(const MCSymbol *, MCStreamer &Out) {
void AArch64MCLFIRewriter::finish(MCStreamer &Out) {
// Flush a deferred LR guard at the end of the stream.
if (DeferredLRGuard && LastSTI) {
- DeferredLRGuard = false;
emitAddMask(AArch64::LR, AArch64::LR, Out, *LastSTI);
+ DeferredLRGuard = false;
}
}
@@ -948,8 +951,8 @@ void AArch64MCLFIRewriter::doRewriteInst(const MCInst &Inst, MCStreamer &Out,
// modified LR is sandboxed before it can be used to transfer control.
if (DeferredLRGuard && (isReturn(Inst) || isIndirectBranch(Inst) ||
isCall(Inst) || isBranch(Inst))) {
- DeferredLRGuard = false;
emitAddMask(AArch64::LR, AArch64::LR, Out, STI);
+ DeferredLRGuard = false;
}
// PAC authenticated branches/calls expand to authenticate + guarded branch.
More information about the llvm-commits
mailing list