[llvm] [ASan] Don't mark alloca as safe if address escapes to callee (PR #178591)

via llvm-commits llvm-commits at lists.llvm.org
Fri Jan 30 09:51:39 PST 2026


https://github.com/mugiwaraluffy56 updated https://github.com/llvm/llvm-project/pull/178591

>From 512ea5f9904dc016799a8d511cdc852aba778243 Mon Sep 17 00:00:00 2001
From: mugiwaraluffy56 <myakampuneeth at gmail.com>
Date: Thu, 29 Jan 2026 10:07:25 +0530
Subject: [PATCH] [ASan] Don't mark alloca as safe if address escapes to callee

Stack safety analysis was marking allocas as 'safe' when all accesses
were in-bounds, even if the alloca's address was passed to another
function. This caused ASan to skip instrumenting the alloca, but the
callee's accesses would still be instrumented, leading to potential
false positives from uninitialized shadow memory.

Fixes #178576

Co-Authored-By: Claude <noreply at anthropic.com>
---
 llvm/lib/Analysis/StackSafetyAnalysis.cpp     |  6 ++-
 .../asan-stack-safety-escape.ll               | 43 +++++++++++++++++++
 2 files changed, 48 insertions(+), 1 deletion(-)
 create mode 100644 llvm/test/Instrumentation/AddressSanitizer/asan-stack-safety-escape.ll

diff --git a/llvm/lib/Analysis/StackSafetyAnalysis.cpp b/llvm/lib/Analysis/StackSafetyAnalysis.cpp
index fbe74d21c7199..9d55a1560e47a 100644
--- a/llvm/lib/Analysis/StackSafetyAnalysis.cpp
+++ b/llvm/lib/Analysis/StackSafetyAnalysis.cpp
@@ -920,7 +920,11 @@ const StackSafetyGlobalInfo::InfoTy &StackSafetyGlobalInfo::getInfo() const {
         ++NumAllocaTotal;
         const AllocaInst *AI = KV.first;
         auto AIRange = getStaticAllocaSizeRange(*AI);
-        if (AIRange.contains(KV.second.Range)) {
+        // An alloca is safe if all accesses are in-bounds AND the address
+        // doesn't escape to other functions. If the address is passed to
+        // another function, ASan may instrument accesses in the callee, which
+        // requires the caller to properly initialize shadow memory.
+        if (AIRange.contains(KV.second.Range) && KV.second.Calls.empty()) {
           Info->SafeAllocas.insert(AI);
           ++NumAllocaStackSafe;
         }
diff --git a/llvm/test/Instrumentation/AddressSanitizer/asan-stack-safety-escape.ll b/llvm/test/Instrumentation/AddressSanitizer/asan-stack-safety-escape.ll
new file mode 100644
index 0000000000000..060e903a3ce5a
--- /dev/null
+++ b/llvm/test/Instrumentation/AddressSanitizer/asan-stack-safety-escape.ll
@@ -0,0 +1,43 @@
+; REQUIRES: x86-registered-target
+;
+; Test that allocas whose addresses escape to another function are still
+; instrumented by ASan, even if all accesses are in-bounds.
+;
+; This is a regression test for https://github.com/llvm/llvm-project/issues/178576
+; where passing an alloca's address to a function that performs a load on it
+; would cause a false positive. The callee's load would be instrumented by ASan,
+; but the caller's alloca would not be (because it was considered "safe"),
+; leaving the shadow memory uninitialized.
+
+; RUN: opt < %s -S -passes=asan -asan-use-stack-safety=1 -o - | FileCheck %s
+
+target datalayout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-unknown-linux-gnu"
+
+; Function that loads from a pointer parameter - ASan will instrument this load.
+; If the caller's alloca is not instrumented, the shadow memory will be uninitialized.
+declare void @func(ptr %ptr)
+
+; CHECK-LABEL: define void @caller
+define void @caller() sanitize_address {
+entry:
+  ; The alloca's address escapes via the call to @func.
+  ; Even though all direct accesses are in-bounds, we must instrument this
+  ; alloca so that shadow memory is properly initialized for the callee.
+  ; CHECK: call i64 @__asan_stack_malloc
+  %ptr = alloca ptr, align 8
+  store ptr null, ptr %ptr, align 8
+  call void @func(ptr %ptr)
+  ret void
+}
+
+; Test case where the alloca's address does NOT escape - should still be optimized.
+; CHECK-LABEL: define i32 @no_escape
+define i32 @no_escape() sanitize_address {
+entry:
+  ; No call passes the address, so this alloca can remain uninstrumented.
+  ; CHECK-NOT: call i64 @__asan_stack_malloc
+  %buf = alloca [10 x i8], align 1
+  %0 = load volatile i8, ptr %buf, align 1
+  ret i32 0
+}



More information about the llvm-commits mailing list