[compiler-rt] Add API to temporalily disable usage of ASAN's fake stack (PR #160135)
Vitaly Buka via llvm-commits
llvm-commits at lists.llvm.org
Wed Oct 15 19:07:58 PDT 2025
https://github.com/vitalybuka updated https://github.com/llvm/llvm-project/pull/160135
>From 4e728017929bfa33edb2bd0a6c82f8f25468c22c Mon Sep 17 00:00:00 2001
From: Wiktor Garbacz <wiktorg at google.com>
Date: Tue, 16 Sep 2025 13:51:08 +0200
Subject: [PATCH 1/3] Add API to temporalily disable usage of ASAN's fake stack
Intended use-case is for threads that use (or switch to) stack
with special properties e.g. backed by MADV_DONTDUMP memory.
---
.../include/sanitizer/asan_interface.h | 7 ++++
compiler-rt/lib/asan/asan_fake_stack.cpp | 39 +++++++++++++++----
compiler-rt/lib/asan/asan_fake_stack.h | 4 +-
compiler-rt/lib/asan/asan_interface.inc | 2 +
compiler-rt/lib/asan/asan_thread.cpp | 7 ++--
compiler-rt/lib/asan/asan_thread.h | 11 +++++-
compiler-rt/lib/asan_abi/asan_abi.cpp | 2 +
compiler-rt/lib/asan_abi/asan_abi.h | 3 ++
compiler-rt/lib/asan_abi/asan_abi_shim.cpp | 2 +
.../asan/TestCases/disable_fake_stack.cpp | 28 +++++++++++++
10 files changed, 93 insertions(+), 12 deletions(-)
create mode 100644 compiler-rt/test/asan/TestCases/disable_fake_stack.cpp
diff --git a/compiler-rt/include/sanitizer/asan_interface.h b/compiler-rt/include/sanitizer/asan_interface.h
index 37b6d08f4db19..a6e8fcd76348e 100644
--- a/compiler-rt/include/sanitizer/asan_interface.h
+++ b/compiler-rt/include/sanitizer/asan_interface.h
@@ -333,6 +333,13 @@ void SANITIZER_CDECL __asan_handle_no_return(void);
/// trace. Returns 1 if successful, 0 if not.
int SANITIZER_CDECL __asan_update_allocation_context(void *addr);
+/// Disables fake stack for the current thread.
+/// Temporarily disables use-after-return detection for current thread.
+void SANITIZER_CDECL __asan_disable_fake_stack(void);
+
+/// (Re)enables fake stack for the current thread.
+void SANITIZER_CDECL __asan_enable_fake_stack(void);
+
#ifdef __cplusplus
} // extern "C"
#endif
diff --git a/compiler-rt/lib/asan/asan_fake_stack.cpp b/compiler-rt/lib/asan/asan_fake_stack.cpp
index c3ed2526f0ed4..dc73c8ee7d4e6 100644
--- a/compiler-rt/lib/asan/asan_fake_stack.cpp
+++ b/compiler-rt/lib/asan/asan_fake_stack.cpp
@@ -217,26 +217,44 @@ static THREADLOCAL FakeStack *fake_stack_tls;
FakeStack *GetTLSFakeStack() {
return fake_stack_tls;
}
-void SetTLSFakeStack(FakeStack *fs) {
+void SetTLSFakeStack(AsanThread* t, FakeStack* fs) {
+ if (fs && !t->IsFakeStackEnabled()) {
+ return;
+ }
fake_stack_tls = fs;
}
#else
FakeStack *GetTLSFakeStack() { return 0; }
-void SetTLSFakeStack(FakeStack *fs) { }
+void SetTLSFakeStack(AsanThread* t, FakeStack* fs) {}
#endif // (SANITIZER_LINUX && !SANITIZER_ANDROID) || SANITIZER_FUCHSIA
-static FakeStack *GetFakeStack() {
+static void DisableFakeStack() {
AsanThread *t = GetCurrentThread();
- if (!t) return nullptr;
+ if (t) {
+ t->SetFakeStackEnabled(false);
+ }
+}
+
+static void EnableFakeStack() {
+ AsanThread* t = GetCurrentThread();
+ if (t) {
+ t->SetFakeStackEnabled(true);
+ }
+}
+
+static FakeStack* GetFakeStack(bool for_allocation = true) {
+ AsanThread* t = GetCurrentThread();
+ if (!t || (for_allocation && !t->IsFakeStackEnabled()))
+ return nullptr;
return t->get_or_create_fake_stack();
}
-static FakeStack *GetFakeStackFast() {
+static FakeStack* GetFakeStackFast(bool for_allocation = true) {
if (FakeStack *fs = GetTLSFakeStack())
return fs;
if (!__asan_option_detect_stack_use_after_return)
return nullptr;
- return GetFakeStack();
+ return GetFakeStack(for_allocation);
}
static FakeStack *GetFakeStackFastAlways() {
@@ -311,7 +329,9 @@ extern "C" {
// -asan-use-after-return=never, after modal UAR flag lands
// (https://github.com/google/sanitizers/issues/1394)
SANITIZER_INTERFACE_ATTRIBUTE
-void *__asan_get_current_fake_stack() { return GetFakeStackFast(); }
+void* __asan_get_current_fake_stack() {
+ return GetFakeStackFast(/*for_allocation=*/false);
+}
SANITIZER_INTERFACE_ATTRIBUTE
void *__asan_addr_is_in_fake_stack(void *fake_stack, void *addr, void **beg,
@@ -349,4 +369,9 @@ void __asan_allocas_unpoison(uptr top, uptr bottom) {
(reinterpret_cast<void *>(MemToShadow(top)), 0,
(bottom - top) / ASAN_SHADOW_GRANULARITY);
}
+
+SANITIZER_INTERFACE_ATTRIBUTE
+void __asan_disable_fake_stack() { return DisableFakeStack(); }
+SANITIZER_INTERFACE_ATTRIBUTE
+void __asan_enable_fake_stack() { return EnableFakeStack(); }
} // extern "C"
diff --git a/compiler-rt/lib/asan/asan_fake_stack.h b/compiler-rt/lib/asan/asan_fake_stack.h
index 50706e6e5876c..1399ef1380ad5 100644
--- a/compiler-rt/lib/asan/asan_fake_stack.h
+++ b/compiler-rt/lib/asan/asan_fake_stack.h
@@ -18,6 +18,8 @@
namespace __asan {
+class AsanThread;
+
// Fake stack frame contains local variables of one function.
struct FakeFrame {
uptr magic; // Modified by the instrumented code.
@@ -196,7 +198,7 @@ class FakeStack {
};
FakeStack *GetTLSFakeStack();
-void SetTLSFakeStack(FakeStack *fs);
+void SetTLSFakeStack(AsanThread* t, FakeStack* fs);
} // namespace __asan
diff --git a/compiler-rt/lib/asan/asan_interface.inc b/compiler-rt/lib/asan/asan_interface.inc
index bfc44b4619623..1f128b7720841 100644
--- a/compiler-rt/lib/asan/asan_interface.inc
+++ b/compiler-rt/lib/asan/asan_interface.inc
@@ -15,6 +15,8 @@ INTERFACE_FUNCTION(__asan_alloca_poison)
INTERFACE_FUNCTION(__asan_allocas_unpoison)
INTERFACE_FUNCTION(__asan_before_dynamic_init)
INTERFACE_FUNCTION(__asan_describe_address)
+INTERFACE_FUNCTION(__asan_disable_fake_stack)
+INTERFACE_FUNCTION(__asan_enable_fake_stack)
INTERFACE_FUNCTION(__asan_exp_load1)
INTERFACE_FUNCTION(__asan_exp_load2)
INTERFACE_FUNCTION(__asan_exp_load4)
diff --git a/compiler-rt/lib/asan/asan_thread.cpp b/compiler-rt/lib/asan/asan_thread.cpp
index 2627ae1289012..44088b971dc49 100644
--- a/compiler-rt/lib/asan/asan_thread.cpp
+++ b/compiler-rt/lib/asan/asan_thread.cpp
@@ -163,7 +163,7 @@ void AsanThread::StartSwitchFiber(FakeStack **fake_stack_save, uptr bottom,
if (fake_stack_save)
*fake_stack_save = fake_stack_;
fake_stack_ = nullptr;
- SetTLSFakeStack(nullptr);
+ SetTLSFakeStack(this, nullptr);
// if fake_stack_save is null, the fiber will die, delete the fakestack
if (!fake_stack_save && current_fake_stack)
current_fake_stack->Destroy(this->tid());
@@ -177,7 +177,7 @@ void AsanThread::FinishSwitchFiber(FakeStack *fake_stack_save, uptr *bottom_old,
}
if (fake_stack_save) {
- SetTLSFakeStack(fake_stack_save);
+ SetTLSFakeStack(this, fake_stack_save);
fake_stack_ = fake_stack_save;
}
@@ -242,7 +242,7 @@ FakeStack *AsanThread::AsyncSignalSafeLazyInitFakeStack() {
Max(stack_size_log, static_cast<uptr>(flags()->min_uar_stack_size_log));
fake_stack_ = FakeStack::Create(stack_size_log);
DCHECK_EQ(GetCurrentThread(), this);
- SetTLSFakeStack(fake_stack_);
+ SetTLSFakeStack(this, fake_stack_);
return fake_stack_;
}
return nullptr;
@@ -251,6 +251,7 @@ FakeStack *AsanThread::AsyncSignalSafeLazyInitFakeStack() {
void AsanThread::Init(const InitOptions *options) {
DCHECK_NE(tid(), kInvalidTid);
next_stack_top_ = next_stack_bottom_ = 0;
+ fake_stack_enabled_ = true;
atomic_store(&stack_switching_, false, memory_order_release);
CHECK_EQ(this->stack_size(), 0U);
SetThreadStackAndTls(options);
diff --git a/compiler-rt/lib/asan/asan_thread.h b/compiler-rt/lib/asan/asan_thread.h
index 12f0cc7a62dae..cb6b3e31b41d6 100644
--- a/compiler-rt/lib/asan/asan_thread.h
+++ b/compiler-rt/lib/asan/asan_thread.h
@@ -104,7 +104,7 @@ class AsanThread {
if (!fake_stack_) return;
FakeStack *t = fake_stack_;
fake_stack_ = nullptr;
- SetTLSFakeStack(nullptr);
+ SetTLSFakeStack(this, nullptr);
t->Destroy(tid);
}
@@ -144,6 +144,14 @@ class AsanThread {
GetStartData(&data, sizeof(data));
}
+ bool IsFakeStackEnabled() const { return fake_stack_enabled_; }
+ void SetFakeStackEnabled(bool enabled) {
+ fake_stack_enabled_ = enabled;
+ if (!enabled) {
+ SetTLSFakeStack(this, nullptr);
+ }
+ }
+
private:
// NOTE: There is no AsanThread constructor. It is allocated
// via mmap() and *must* be valid in zero-initialized state.
@@ -179,6 +187,7 @@ class AsanThread {
DTLS *dtls_;
FakeStack *fake_stack_;
+ bool fake_stack_enabled_;
AsanThreadLocalMallocStorage malloc_storage_;
AsanStats stats_;
bool unwinding_;
diff --git a/compiler-rt/lib/asan_abi/asan_abi.cpp b/compiler-rt/lib/asan_abi/asan_abi.cpp
index cf8663024eb73..1e0126fcdceea 100644
--- a/compiler-rt/lib/asan_abi/asan_abi.cpp
+++ b/compiler-rt/lib/asan_abi/asan_abi.cpp
@@ -73,6 +73,8 @@ void *__asan_abi_addr_is_in_fake_stack(void *fake_stack, void *addr, void **beg,
void **end) {
return NULL;
}
+void __asan_abi_disable_fake_stack(void) {}
+void __asan_abi_enable_fake_stack(void) {}
// Functions concerning poisoning and unpoisoning fake stack alloca
void __asan_abi_alloca_poison(void *addr, size_t size) {}
diff --git a/compiler-rt/lib/asan_abi/asan_abi.h b/compiler-rt/lib/asan_abi/asan_abi.h
index 8702bcd133919..e8b8cd06926dd 100644
--- a/compiler-rt/lib/asan_abi/asan_abi.h
+++ b/compiler-rt/lib/asan_abi/asan_abi.h
@@ -76,6 +76,9 @@ void *__asan_abi_load_cxx_array_cookie(void **p);
void *__asan_abi_get_current_fake_stack();
void *__asan_abi_addr_is_in_fake_stack(void *fake_stack, void *addr, void **beg,
void **end);
+void *__asan_abi_disable_fake_stack();
+void *__asan_abi_enable_fake_stack();
+
// Functions concerning poisoning and unpoisoning fake stack alloca
void __asan_abi_alloca_poison(void *addr, size_t size);
void __asan_abi_allocas_unpoison(void *top, void *bottom);
diff --git a/compiler-rt/lib/asan_abi/asan_abi_shim.cpp b/compiler-rt/lib/asan_abi/asan_abi_shim.cpp
index 2512abc641250..eea415294ca77 100644
--- a/compiler-rt/lib/asan_abi/asan_abi_shim.cpp
+++ b/compiler-rt/lib/asan_abi/asan_abi_shim.cpp
@@ -365,6 +365,8 @@ void *__asan_addr_is_in_fake_stack(void *fake_stack, void *addr, void **beg,
void **end) {
return __asan_abi_addr_is_in_fake_stack(fake_stack, addr, beg, end);
}
+void __asan_disable_fake_stack(void) { return __asan_abi_disable_fake_stack(); }
+void __asan_enable_fake_stack(void) { return __asan_abi_enable_fake_stack(); }
// Functions concerning poisoning and unpoisoning fake stack alloca
void __asan_alloca_poison(uptr addr, uptr size) {
diff --git a/compiler-rt/test/asan/TestCases/disable_fake_stack.cpp b/compiler-rt/test/asan/TestCases/disable_fake_stack.cpp
new file mode 100644
index 0000000000000..a7e2cb4ca44b8
--- /dev/null
+++ b/compiler-rt/test/asan/TestCases/disable_fake_stack.cpp
@@ -0,0 +1,28 @@
+// RUN: %clangxx_asan %s -o %t && %run %t
+
+#include "defines.h"
+
+#include <sanitizer/asan_interface.h>
+
+volatile char *saved;
+
+ATTRIBUTE_NOINLINE bool IsOnStack() {
+ volatile char temp = ' ';
+ void *fake_stack = __asan_get_current_fake_stack();
+ void *real = __asan_addr_is_in_fake_stack(
+ fake_stack, const_cast<char *>(&temp), nullptr, nullptr);
+ saved = &temp;
+ return real == nullptr;
+}
+
+int main(int argc, char *argv[]) {
+ __asan_disable_fake_stack();
+ if (!IsOnStack()) {
+ return 1;
+ }
+ __asan_enable_fake_stack();
+ if (IsOnStack()) {
+ return 2;
+ }
+ return 0;
+}
>From c10e56827560a4c2b13f9aae54d8be025373fd38 Mon Sep 17 00:00:00 2001
From: Wiktor Garbacz <wiktorg at google.com>
Date: Tue, 16 Sep 2025 13:51:08 +0200
Subject: [PATCH 2/3] Add API to temporalily disable usage of ASAN's fake stack
Intended use-case is for threads that use (or switch to) stack
with special properties e.g. backed by MADV_DONTDUMP memory.
---
.../include/sanitizer/asan_interface.h | 7 +++++
compiler-rt/lib/asan/asan_fake_stack.cpp | 27 ++++++++++++++++--
compiler-rt/lib/asan/asan_interface.inc | 2 ++
compiler-rt/lib/asan/asan_thread.cpp | 1 +
compiler-rt/lib/asan/asan_thread.h | 7 +++++
compiler-rt/lib/asan_abi/asan_abi.cpp | 2 ++
compiler-rt/lib/asan_abi/asan_abi.h | 3 ++
compiler-rt/lib/asan_abi/asan_abi_shim.cpp | 2 ++
.../asan/TestCases/disable_fake_stack.cpp | 28 +++++++++++++++++++
9 files changed, 76 insertions(+), 3 deletions(-)
create mode 100644 compiler-rt/test/asan/TestCases/disable_fake_stack.cpp
diff --git a/compiler-rt/include/sanitizer/asan_interface.h b/compiler-rt/include/sanitizer/asan_interface.h
index 37b6d08f4db19..a6e8fcd76348e 100644
--- a/compiler-rt/include/sanitizer/asan_interface.h
+++ b/compiler-rt/include/sanitizer/asan_interface.h
@@ -333,6 +333,13 @@ void SANITIZER_CDECL __asan_handle_no_return(void);
/// trace. Returns 1 if successful, 0 if not.
int SANITIZER_CDECL __asan_update_allocation_context(void *addr);
+/// Disables fake stack for the current thread.
+/// Temporarily disables use-after-return detection for current thread.
+void SANITIZER_CDECL __asan_disable_fake_stack(void);
+
+/// (Re)enables fake stack for the current thread.
+void SANITIZER_CDECL __asan_enable_fake_stack(void);
+
#ifdef __cplusplus
} // extern "C"
#endif
diff --git a/compiler-rt/lib/asan/asan_fake_stack.cpp b/compiler-rt/lib/asan/asan_fake_stack.cpp
index d3fa953f31005..ad738b0d8168c 100644
--- a/compiler-rt/lib/asan/asan_fake_stack.cpp
+++ b/compiler-rt/lib/asan/asan_fake_stack.cpp
@@ -217,17 +217,33 @@ void FakeStack::ForEachFakeFrame(RangeIteratorCallback callback, void* arg) {
static THREADLOCAL FakeStack* fake_stack_tls;
static FakeStack* GetTLSFakeStack() { return fake_stack_tls; }
-static void SetTLSFakeStack(FakeStack* fs) { fake_stack_tls = fs; }
+static void SetTLSFakeStack(FakeStack* fs) {
+ fake_stack_tls = fs;
+}
void ResetTLSFakeStack() { fake_stack_tls = nullptr; }
#else
static FakeStack* GetTLSFakeStack() { return nullptr; }
-static void SetTLSFakeStack(FakeStack*) {}
+static void SetTLSFakeStack(FakeStack* fs) {}
void ResetTLSFakeStack() {}
#endif // (SANITIZER_LINUX && !SANITIZER_ANDROID) || SANITIZER_FUCHSIA
+static void DisableFakeStack() {
+ AsanThread* t = GetCurrentThread();
+ if (t) {
+ t->SetFakeStackEnabled(false);
+ }
+}
+
+static void EnableFakeStack() {
+ AsanThread* t = GetCurrentThread();
+ if (t) {
+ t->SetFakeStackEnabled(true);
+ }
+}
+
static FakeStack* GetFakeStack() {
AsanThread* t = GetCurrentThread();
- if (!t)
+ if (!t || !t->IsFakeStackEnabled())
return nullptr;
return t->get_or_create_fake_stack();
}
@@ -362,4 +378,9 @@ void __asan_allocas_unpoison(uptr top, uptr bottom) {
REAL(memset)(reinterpret_cast<void*>(MemToShadow(top)), 0,
(bottom - top) / ASAN_SHADOW_GRANULARITY);
}
+
+SANITIZER_INTERFACE_ATTRIBUTE
+void __asan_disable_fake_stack() { return DisableFakeStack(); }
+SANITIZER_INTERFACE_ATTRIBUTE
+void __asan_enable_fake_stack() { return EnableFakeStack(); }
} // extern "C"
diff --git a/compiler-rt/lib/asan/asan_interface.inc b/compiler-rt/lib/asan/asan_interface.inc
index bfc44b4619623..1f128b7720841 100644
--- a/compiler-rt/lib/asan/asan_interface.inc
+++ b/compiler-rt/lib/asan/asan_interface.inc
@@ -15,6 +15,8 @@ INTERFACE_FUNCTION(__asan_alloca_poison)
INTERFACE_FUNCTION(__asan_allocas_unpoison)
INTERFACE_FUNCTION(__asan_before_dynamic_init)
INTERFACE_FUNCTION(__asan_describe_address)
+INTERFACE_FUNCTION(__asan_disable_fake_stack)
+INTERFACE_FUNCTION(__asan_enable_fake_stack)
INTERFACE_FUNCTION(__asan_exp_load1)
INTERFACE_FUNCTION(__asan_exp_load2)
INTERFACE_FUNCTION(__asan_exp_load4)
diff --git a/compiler-rt/lib/asan/asan_thread.cpp b/compiler-rt/lib/asan/asan_thread.cpp
index 0ed58bbe2a73a..17836c8c4b404 100644
--- a/compiler-rt/lib/asan/asan_thread.cpp
+++ b/compiler-rt/lib/asan/asan_thread.cpp
@@ -251,6 +251,7 @@ FakeStack *AsanThread::AsyncSignalSafeLazyInitFakeStack() {
void AsanThread::Init(const InitOptions *options) {
DCHECK_NE(tid(), kInvalidTid);
next_stack_top_ = next_stack_bottom_ = 0;
+ fake_stack_enabled_ = true;
atomic_store(&stack_switching_, false, memory_order_release);
CHECK_EQ(this->stack_size(), 0U);
SetThreadStackAndTls(options);
diff --git a/compiler-rt/lib/asan/asan_thread.h b/compiler-rt/lib/asan/asan_thread.h
index 19b7f342e1712..1c951b757ba00 100644
--- a/compiler-rt/lib/asan/asan_thread.h
+++ b/compiler-rt/lib/asan/asan_thread.h
@@ -144,6 +144,12 @@ class AsanThread {
GetStartData(&data, sizeof(data));
}
+ bool IsFakeStackEnabled() const { return fake_stack_enabled_; }
+ void SetFakeStackEnabled(bool enabled) {
+ fake_stack_enabled_ = enabled;
+ ResetTLSFakeStack();
+ }
+
private:
// NOTE: There is no AsanThread constructor. It is allocated
// via mmap() and *must* be valid in zero-initialized state.
@@ -179,6 +185,7 @@ class AsanThread {
DTLS *dtls_;
FakeStack *fake_stack_;
+ bool fake_stack_enabled_;
AsanThreadLocalMallocStorage malloc_storage_;
AsanStats stats_;
bool unwinding_;
diff --git a/compiler-rt/lib/asan_abi/asan_abi.cpp b/compiler-rt/lib/asan_abi/asan_abi.cpp
index cf8663024eb73..1e0126fcdceea 100644
--- a/compiler-rt/lib/asan_abi/asan_abi.cpp
+++ b/compiler-rt/lib/asan_abi/asan_abi.cpp
@@ -73,6 +73,8 @@ void *__asan_abi_addr_is_in_fake_stack(void *fake_stack, void *addr, void **beg,
void **end) {
return NULL;
}
+void __asan_abi_disable_fake_stack(void) {}
+void __asan_abi_enable_fake_stack(void) {}
// Functions concerning poisoning and unpoisoning fake stack alloca
void __asan_abi_alloca_poison(void *addr, size_t size) {}
diff --git a/compiler-rt/lib/asan_abi/asan_abi.h b/compiler-rt/lib/asan_abi/asan_abi.h
index 8702bcd133919..e8b8cd06926dd 100644
--- a/compiler-rt/lib/asan_abi/asan_abi.h
+++ b/compiler-rt/lib/asan_abi/asan_abi.h
@@ -76,6 +76,9 @@ void *__asan_abi_load_cxx_array_cookie(void **p);
void *__asan_abi_get_current_fake_stack();
void *__asan_abi_addr_is_in_fake_stack(void *fake_stack, void *addr, void **beg,
void **end);
+void *__asan_abi_disable_fake_stack();
+void *__asan_abi_enable_fake_stack();
+
// Functions concerning poisoning and unpoisoning fake stack alloca
void __asan_abi_alloca_poison(void *addr, size_t size);
void __asan_abi_allocas_unpoison(void *top, void *bottom);
diff --git a/compiler-rt/lib/asan_abi/asan_abi_shim.cpp b/compiler-rt/lib/asan_abi/asan_abi_shim.cpp
index 2512abc641250..eea415294ca77 100644
--- a/compiler-rt/lib/asan_abi/asan_abi_shim.cpp
+++ b/compiler-rt/lib/asan_abi/asan_abi_shim.cpp
@@ -365,6 +365,8 @@ void *__asan_addr_is_in_fake_stack(void *fake_stack, void *addr, void **beg,
void **end) {
return __asan_abi_addr_is_in_fake_stack(fake_stack, addr, beg, end);
}
+void __asan_disable_fake_stack(void) { return __asan_abi_disable_fake_stack(); }
+void __asan_enable_fake_stack(void) { return __asan_abi_enable_fake_stack(); }
// Functions concerning poisoning and unpoisoning fake stack alloca
void __asan_alloca_poison(uptr addr, uptr size) {
diff --git a/compiler-rt/test/asan/TestCases/disable_fake_stack.cpp b/compiler-rt/test/asan/TestCases/disable_fake_stack.cpp
new file mode 100644
index 0000000000000..a7e2cb4ca44b8
--- /dev/null
+++ b/compiler-rt/test/asan/TestCases/disable_fake_stack.cpp
@@ -0,0 +1,28 @@
+// RUN: %clangxx_asan %s -o %t && %run %t
+
+#include "defines.h"
+
+#include <sanitizer/asan_interface.h>
+
+volatile char *saved;
+
+ATTRIBUTE_NOINLINE bool IsOnStack() {
+ volatile char temp = ' ';
+ void *fake_stack = __asan_get_current_fake_stack();
+ void *real = __asan_addr_is_in_fake_stack(
+ fake_stack, const_cast<char *>(&temp), nullptr, nullptr);
+ saved = &temp;
+ return real == nullptr;
+}
+
+int main(int argc, char *argv[]) {
+ __asan_disable_fake_stack();
+ if (!IsOnStack()) {
+ return 1;
+ }
+ __asan_enable_fake_stack();
+ if (IsOnStack()) {
+ return 2;
+ }
+ return 0;
+}
>From 0769e3d420a364d6ed9661d6a3533333104ba24d Mon Sep 17 00:00:00 2001
From: Vitaly Buka <vitalybuka at google.com>
Date: Wed, 15 Oct 2025 19:02:01 -0700
Subject: [PATCH 3/3] Revert "Add API to temporalily disable usage of ASAN's
fake stack"
This reverts commit 4e728017929bfa33edb2bd0a6c82f8f25468c22c.
---
.../include/sanitizer/asan_interface.h | 7 ----
compiler-rt/lib/asan/asan_fake_stack.cpp | 39 ++++---------------
compiler-rt/lib/asan/asan_fake_stack.h | 4 +-
compiler-rt/lib/asan/asan_interface.inc | 2 -
compiler-rt/lib/asan/asan_thread.cpp | 7 ++--
compiler-rt/lib/asan/asan_thread.h | 11 +-----
compiler-rt/lib/asan_abi/asan_abi.cpp | 2 -
compiler-rt/lib/asan_abi/asan_abi.h | 3 --
compiler-rt/lib/asan_abi/asan_abi_shim.cpp | 2 -
.../asan/TestCases/disable_fake_stack.cpp | 28 -------------
10 files changed, 12 insertions(+), 93 deletions(-)
delete mode 100644 compiler-rt/test/asan/TestCases/disable_fake_stack.cpp
diff --git a/compiler-rt/include/sanitizer/asan_interface.h b/compiler-rt/include/sanitizer/asan_interface.h
index a6e8fcd76348e..37b6d08f4db19 100644
--- a/compiler-rt/include/sanitizer/asan_interface.h
+++ b/compiler-rt/include/sanitizer/asan_interface.h
@@ -333,13 +333,6 @@ void SANITIZER_CDECL __asan_handle_no_return(void);
/// trace. Returns 1 if successful, 0 if not.
int SANITIZER_CDECL __asan_update_allocation_context(void *addr);
-/// Disables fake stack for the current thread.
-/// Temporarily disables use-after-return detection for current thread.
-void SANITIZER_CDECL __asan_disable_fake_stack(void);
-
-/// (Re)enables fake stack for the current thread.
-void SANITIZER_CDECL __asan_enable_fake_stack(void);
-
#ifdef __cplusplus
} // extern "C"
#endif
diff --git a/compiler-rt/lib/asan/asan_fake_stack.cpp b/compiler-rt/lib/asan/asan_fake_stack.cpp
index dc73c8ee7d4e6..c3ed2526f0ed4 100644
--- a/compiler-rt/lib/asan/asan_fake_stack.cpp
+++ b/compiler-rt/lib/asan/asan_fake_stack.cpp
@@ -217,44 +217,26 @@ static THREADLOCAL FakeStack *fake_stack_tls;
FakeStack *GetTLSFakeStack() {
return fake_stack_tls;
}
-void SetTLSFakeStack(AsanThread* t, FakeStack* fs) {
- if (fs && !t->IsFakeStackEnabled()) {
- return;
- }
+void SetTLSFakeStack(FakeStack *fs) {
fake_stack_tls = fs;
}
#else
FakeStack *GetTLSFakeStack() { return 0; }
-void SetTLSFakeStack(AsanThread* t, FakeStack* fs) {}
+void SetTLSFakeStack(FakeStack *fs) { }
#endif // (SANITIZER_LINUX && !SANITIZER_ANDROID) || SANITIZER_FUCHSIA
-static void DisableFakeStack() {
+static FakeStack *GetFakeStack() {
AsanThread *t = GetCurrentThread();
- if (t) {
- t->SetFakeStackEnabled(false);
- }
-}
-
-static void EnableFakeStack() {
- AsanThread* t = GetCurrentThread();
- if (t) {
- t->SetFakeStackEnabled(true);
- }
-}
-
-static FakeStack* GetFakeStack(bool for_allocation = true) {
- AsanThread* t = GetCurrentThread();
- if (!t || (for_allocation && !t->IsFakeStackEnabled()))
- return nullptr;
+ if (!t) return nullptr;
return t->get_or_create_fake_stack();
}
-static FakeStack* GetFakeStackFast(bool for_allocation = true) {
+static FakeStack *GetFakeStackFast() {
if (FakeStack *fs = GetTLSFakeStack())
return fs;
if (!__asan_option_detect_stack_use_after_return)
return nullptr;
- return GetFakeStack(for_allocation);
+ return GetFakeStack();
}
static FakeStack *GetFakeStackFastAlways() {
@@ -329,9 +311,7 @@ extern "C" {
// -asan-use-after-return=never, after modal UAR flag lands
// (https://github.com/google/sanitizers/issues/1394)
SANITIZER_INTERFACE_ATTRIBUTE
-void* __asan_get_current_fake_stack() {
- return GetFakeStackFast(/*for_allocation=*/false);
-}
+void *__asan_get_current_fake_stack() { return GetFakeStackFast(); }
SANITIZER_INTERFACE_ATTRIBUTE
void *__asan_addr_is_in_fake_stack(void *fake_stack, void *addr, void **beg,
@@ -369,9 +349,4 @@ void __asan_allocas_unpoison(uptr top, uptr bottom) {
(reinterpret_cast<void *>(MemToShadow(top)), 0,
(bottom - top) / ASAN_SHADOW_GRANULARITY);
}
-
-SANITIZER_INTERFACE_ATTRIBUTE
-void __asan_disable_fake_stack() { return DisableFakeStack(); }
-SANITIZER_INTERFACE_ATTRIBUTE
-void __asan_enable_fake_stack() { return EnableFakeStack(); }
} // extern "C"
diff --git a/compiler-rt/lib/asan/asan_fake_stack.h b/compiler-rt/lib/asan/asan_fake_stack.h
index 1399ef1380ad5..50706e6e5876c 100644
--- a/compiler-rt/lib/asan/asan_fake_stack.h
+++ b/compiler-rt/lib/asan/asan_fake_stack.h
@@ -18,8 +18,6 @@
namespace __asan {
-class AsanThread;
-
// Fake stack frame contains local variables of one function.
struct FakeFrame {
uptr magic; // Modified by the instrumented code.
@@ -198,7 +196,7 @@ class FakeStack {
};
FakeStack *GetTLSFakeStack();
-void SetTLSFakeStack(AsanThread* t, FakeStack* fs);
+void SetTLSFakeStack(FakeStack *fs);
} // namespace __asan
diff --git a/compiler-rt/lib/asan/asan_interface.inc b/compiler-rt/lib/asan/asan_interface.inc
index 1f128b7720841..bfc44b4619623 100644
--- a/compiler-rt/lib/asan/asan_interface.inc
+++ b/compiler-rt/lib/asan/asan_interface.inc
@@ -15,8 +15,6 @@ INTERFACE_FUNCTION(__asan_alloca_poison)
INTERFACE_FUNCTION(__asan_allocas_unpoison)
INTERFACE_FUNCTION(__asan_before_dynamic_init)
INTERFACE_FUNCTION(__asan_describe_address)
-INTERFACE_FUNCTION(__asan_disable_fake_stack)
-INTERFACE_FUNCTION(__asan_enable_fake_stack)
INTERFACE_FUNCTION(__asan_exp_load1)
INTERFACE_FUNCTION(__asan_exp_load2)
INTERFACE_FUNCTION(__asan_exp_load4)
diff --git a/compiler-rt/lib/asan/asan_thread.cpp b/compiler-rt/lib/asan/asan_thread.cpp
index 44088b971dc49..2627ae1289012 100644
--- a/compiler-rt/lib/asan/asan_thread.cpp
+++ b/compiler-rt/lib/asan/asan_thread.cpp
@@ -163,7 +163,7 @@ void AsanThread::StartSwitchFiber(FakeStack **fake_stack_save, uptr bottom,
if (fake_stack_save)
*fake_stack_save = fake_stack_;
fake_stack_ = nullptr;
- SetTLSFakeStack(this, nullptr);
+ SetTLSFakeStack(nullptr);
// if fake_stack_save is null, the fiber will die, delete the fakestack
if (!fake_stack_save && current_fake_stack)
current_fake_stack->Destroy(this->tid());
@@ -177,7 +177,7 @@ void AsanThread::FinishSwitchFiber(FakeStack *fake_stack_save, uptr *bottom_old,
}
if (fake_stack_save) {
- SetTLSFakeStack(this, fake_stack_save);
+ SetTLSFakeStack(fake_stack_save);
fake_stack_ = fake_stack_save;
}
@@ -242,7 +242,7 @@ FakeStack *AsanThread::AsyncSignalSafeLazyInitFakeStack() {
Max(stack_size_log, static_cast<uptr>(flags()->min_uar_stack_size_log));
fake_stack_ = FakeStack::Create(stack_size_log);
DCHECK_EQ(GetCurrentThread(), this);
- SetTLSFakeStack(this, fake_stack_);
+ SetTLSFakeStack(fake_stack_);
return fake_stack_;
}
return nullptr;
@@ -251,7 +251,6 @@ FakeStack *AsanThread::AsyncSignalSafeLazyInitFakeStack() {
void AsanThread::Init(const InitOptions *options) {
DCHECK_NE(tid(), kInvalidTid);
next_stack_top_ = next_stack_bottom_ = 0;
- fake_stack_enabled_ = true;
atomic_store(&stack_switching_, false, memory_order_release);
CHECK_EQ(this->stack_size(), 0U);
SetThreadStackAndTls(options);
diff --git a/compiler-rt/lib/asan/asan_thread.h b/compiler-rt/lib/asan/asan_thread.h
index cb6b3e31b41d6..12f0cc7a62dae 100644
--- a/compiler-rt/lib/asan/asan_thread.h
+++ b/compiler-rt/lib/asan/asan_thread.h
@@ -104,7 +104,7 @@ class AsanThread {
if (!fake_stack_) return;
FakeStack *t = fake_stack_;
fake_stack_ = nullptr;
- SetTLSFakeStack(this, nullptr);
+ SetTLSFakeStack(nullptr);
t->Destroy(tid);
}
@@ -144,14 +144,6 @@ class AsanThread {
GetStartData(&data, sizeof(data));
}
- bool IsFakeStackEnabled() const { return fake_stack_enabled_; }
- void SetFakeStackEnabled(bool enabled) {
- fake_stack_enabled_ = enabled;
- if (!enabled) {
- SetTLSFakeStack(this, nullptr);
- }
- }
-
private:
// NOTE: There is no AsanThread constructor. It is allocated
// via mmap() and *must* be valid in zero-initialized state.
@@ -187,7 +179,6 @@ class AsanThread {
DTLS *dtls_;
FakeStack *fake_stack_;
- bool fake_stack_enabled_;
AsanThreadLocalMallocStorage malloc_storage_;
AsanStats stats_;
bool unwinding_;
diff --git a/compiler-rt/lib/asan_abi/asan_abi.cpp b/compiler-rt/lib/asan_abi/asan_abi.cpp
index 1e0126fcdceea..cf8663024eb73 100644
--- a/compiler-rt/lib/asan_abi/asan_abi.cpp
+++ b/compiler-rt/lib/asan_abi/asan_abi.cpp
@@ -73,8 +73,6 @@ void *__asan_abi_addr_is_in_fake_stack(void *fake_stack, void *addr, void **beg,
void **end) {
return NULL;
}
-void __asan_abi_disable_fake_stack(void) {}
-void __asan_abi_enable_fake_stack(void) {}
// Functions concerning poisoning and unpoisoning fake stack alloca
void __asan_abi_alloca_poison(void *addr, size_t size) {}
diff --git a/compiler-rt/lib/asan_abi/asan_abi.h b/compiler-rt/lib/asan_abi/asan_abi.h
index e8b8cd06926dd..8702bcd133919 100644
--- a/compiler-rt/lib/asan_abi/asan_abi.h
+++ b/compiler-rt/lib/asan_abi/asan_abi.h
@@ -76,9 +76,6 @@ void *__asan_abi_load_cxx_array_cookie(void **p);
void *__asan_abi_get_current_fake_stack();
void *__asan_abi_addr_is_in_fake_stack(void *fake_stack, void *addr, void **beg,
void **end);
-void *__asan_abi_disable_fake_stack();
-void *__asan_abi_enable_fake_stack();
-
// Functions concerning poisoning and unpoisoning fake stack alloca
void __asan_abi_alloca_poison(void *addr, size_t size);
void __asan_abi_allocas_unpoison(void *top, void *bottom);
diff --git a/compiler-rt/lib/asan_abi/asan_abi_shim.cpp b/compiler-rt/lib/asan_abi/asan_abi_shim.cpp
index eea415294ca77..2512abc641250 100644
--- a/compiler-rt/lib/asan_abi/asan_abi_shim.cpp
+++ b/compiler-rt/lib/asan_abi/asan_abi_shim.cpp
@@ -365,8 +365,6 @@ void *__asan_addr_is_in_fake_stack(void *fake_stack, void *addr, void **beg,
void **end) {
return __asan_abi_addr_is_in_fake_stack(fake_stack, addr, beg, end);
}
-void __asan_disable_fake_stack(void) { return __asan_abi_disable_fake_stack(); }
-void __asan_enable_fake_stack(void) { return __asan_abi_enable_fake_stack(); }
// Functions concerning poisoning and unpoisoning fake stack alloca
void __asan_alloca_poison(uptr addr, uptr size) {
diff --git a/compiler-rt/test/asan/TestCases/disable_fake_stack.cpp b/compiler-rt/test/asan/TestCases/disable_fake_stack.cpp
deleted file mode 100644
index a7e2cb4ca44b8..0000000000000
--- a/compiler-rt/test/asan/TestCases/disable_fake_stack.cpp
+++ /dev/null
@@ -1,28 +0,0 @@
-// RUN: %clangxx_asan %s -o %t && %run %t
-
-#include "defines.h"
-
-#include <sanitizer/asan_interface.h>
-
-volatile char *saved;
-
-ATTRIBUTE_NOINLINE bool IsOnStack() {
- volatile char temp = ' ';
- void *fake_stack = __asan_get_current_fake_stack();
- void *real = __asan_addr_is_in_fake_stack(
- fake_stack, const_cast<char *>(&temp), nullptr, nullptr);
- saved = &temp;
- return real == nullptr;
-}
-
-int main(int argc, char *argv[]) {
- __asan_disable_fake_stack();
- if (!IsOnStack()) {
- return 1;
- }
- __asan_enable_fake_stack();
- if (IsOnStack()) {
- return 2;
- }
- return 0;
-}
More information about the llvm-commits
mailing list