From 4e728017929bfa33edb2bd0a6c82f8f25468c22c Mon Sep 17 00:00:00 2001 From: Wiktor Garbacz Date: Tue, 16 Sep 2025 13:51:08 +0200 Subject: [PATCH 01/12] 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(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(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 + +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(&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 Date: Tue, 16 Sep 2025 13:51:08 +0200 Subject: [PATCH 02/12] 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(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 + +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(&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 Date: Wed, 15 Oct 2025 19:02:01 -0700 Subject: [PATCH 03/12] 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(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(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 - -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(&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 765703093e7d16e3dd52e2009d614aacb996e557 Mon Sep 17 00:00:00 2001 From: Vitaly Buka Date: Wed, 15 Oct 2025 19:29:42 -0700 Subject: [PATCH 04/12] Update test --- .../asan/TestCases/disable_fake_stack.cpp | 27 ++++++++++--------- 1 file changed, 15 insertions(+), 12 deletions(-) diff --git a/compiler-rt/test/asan/TestCases/disable_fake_stack.cpp b/compiler-rt/test/asan/TestCases/disable_fake_stack.cpp index a7e2cb4ca44b8..1646658302c2e 100644 --- a/compiler-rt/test/asan/TestCases/disable_fake_stack.cpp +++ b/compiler-rt/test/asan/TestCases/disable_fake_stack.cpp @@ -2,27 +2,30 @@ #include "defines.h" +#include #include -volatile char *saved; +volatile uintptr_t saved; + +ATTRIBUTE_NOINLINE bool IsOnRealStack(uintptr_t caller_frame) { + uintptr_t this_frame = reinterpret_cast(__builtin_frame_address(0)); + return this_frame <= saved && saved <= caller_frame; +} 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(&temp), nullptr, nullptr); - saved = &temp; - return real == nullptr; + saved = reinterpret_cast(&temp); + return IsOnRealStack(reinterpret_cast(__builtin_frame_address(0))); } int main(int argc, char *argv[]) { + assert(!IsOnStack()); + __asan_disable_fake_stack(); - if (!IsOnStack()) { - return 1; - } + assert(IsOnStack()); + __asan_enable_fake_stack(); - if (IsOnStack()) { - return 2; - } + assert(!IsOnStack()); + return 0; } From f56cd996ec35e6d876a0aed396f4643fbdf2f4c6 Mon Sep 17 00:00:00 2001 From: Vitaly Buka Date: Wed, 15 Oct 2025 19:32:40 -0700 Subject: [PATCH 05/12] format --- compiler-rt/lib/asan/asan_fake_stack.cpp | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/compiler-rt/lib/asan/asan_fake_stack.cpp b/compiler-rt/lib/asan/asan_fake_stack.cpp index ad738b0d8168c..cbd1ee1f531c4 100644 --- a/compiler-rt/lib/asan/asan_fake_stack.cpp +++ b/compiler-rt/lib/asan/asan_fake_stack.cpp @@ -217,13 +217,11 @@ 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* fs) {} +static void SetTLSFakeStack(FakeStack *fs) {} void ResetTLSFakeStack() {} #endif // (SANITIZER_LINUX && !SANITIZER_ANDROID) || SANITIZER_FUCHSIA From 710eccb708dec3ea2033fc250243c03d24759c0d Mon Sep 17 00:00:00 2001 From: Vitaly Buka Date: Wed, 15 Oct 2025 19:33:04 -0700 Subject: [PATCH 06/12] format --- compiler-rt/lib/asan/asan_fake_stack.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler-rt/lib/asan/asan_fake_stack.cpp b/compiler-rt/lib/asan/asan_fake_stack.cpp index cbd1ee1f531c4..f3d5f938778b3 100644 --- a/compiler-rt/lib/asan/asan_fake_stack.cpp +++ b/compiler-rt/lib/asan/asan_fake_stack.cpp @@ -221,7 +221,7 @@ 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 *fs) {} +static void SetTLSFakeStack(FakeStack*) {} void ResetTLSFakeStack() {} #endif // (SANITIZER_LINUX && !SANITIZER_ANDROID) || SANITIZER_FUCHSIA From 29622a99827879c6a753a02528340ddb391f3c4d Mon Sep 17 00:00:00 2001 From: Vitaly Buka Date: Wed, 15 Oct 2025 19:35:19 -0700 Subject: [PATCH 07/12] format --- compiler-rt/test/asan/TestCases/disable_fake_stack.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/compiler-rt/test/asan/TestCases/disable_fake_stack.cpp b/compiler-rt/test/asan/TestCases/disable_fake_stack.cpp index 1646658302c2e..c7480d1001095 100644 --- a/compiler-rt/test/asan/TestCases/disable_fake_stack.cpp +++ b/compiler-rt/test/asan/TestCases/disable_fake_stack.cpp @@ -8,7 +8,8 @@ volatile uintptr_t saved; ATTRIBUTE_NOINLINE bool IsOnRealStack(uintptr_t caller_frame) { - uintptr_t this_frame = reinterpret_cast(__builtin_frame_address(0)); + uintptr_t this_frame = + reinterpret_cast(__builtin_frame_address(0)); return this_frame <= saved && saved <= caller_frame; } From 42891461fba449cc8203c05ea18653abbee05cf4 Mon Sep 17 00:00:00 2001 From: Wiktor Garbacz Date: Tue, 25 Nov 2025 15:45:32 +0100 Subject: [PATCH 08/12] Add thorough tests --- .../asan/TestCases/disable_fake_stack.cpp | 2 ++ .../disable_fake_stack_force_disabled.cpp | 33 +++++++++++++++++++ 2 files changed, 35 insertions(+) create mode 100644 compiler-rt/test/asan/TestCases/disable_fake_stack_force_disabled.cpp diff --git a/compiler-rt/test/asan/TestCases/disable_fake_stack.cpp b/compiler-rt/test/asan/TestCases/disable_fake_stack.cpp index c7480d1001095..5bfc98314703f 100644 --- a/compiler-rt/test/asan/TestCases/disable_fake_stack.cpp +++ b/compiler-rt/test/asan/TestCases/disable_fake_stack.cpp @@ -1,4 +1,6 @@ // RUN: %clangxx_asan %s -o %t && %run %t +// RUN: %clangxx_asan %s -mllvm -asan-use-after-return=runtime -o %t && env ASAN_OPTIONS=detect_stack_use_after_return=1 %run %t +// RUN: %clangxx_asan %s -mllvm -asan-use-after-return=always -o %t && %run %t #include "defines.h" diff --git a/compiler-rt/test/asan/TestCases/disable_fake_stack_force_disabled.cpp b/compiler-rt/test/asan/TestCases/disable_fake_stack_force_disabled.cpp new file mode 100644 index 0000000000000..91f37e59abff4 --- /dev/null +++ b/compiler-rt/test/asan/TestCases/disable_fake_stack_force_disabled.cpp @@ -0,0 +1,33 @@ +// RUN: %clangxx_asan %s -mllvm -asan-use-after-return=never -o %t && %run %t +// RUN: %clangxx_asan %s -mllvm -asan-use-after-return=runtime -o %t && env ASAN_OPTIONS=detect_stack_use_after_return=0 %run %t + +#include "defines.h" + +#include +#include + +volatile uintptr_t saved; + +ATTRIBUTE_NOINLINE bool IsOnRealStack(uintptr_t caller_frame) { + uintptr_t this_frame = + reinterpret_cast(__builtin_frame_address(0)); + return this_frame <= saved && saved <= caller_frame; +} + +ATTRIBUTE_NOINLINE bool IsOnStack() { + volatile char temp = ' '; + saved = reinterpret_cast(&temp); + return IsOnRealStack(reinterpret_cast(__builtin_frame_address(0))); +} + +int main(int argc, char *argv[]) { + assert(IsOnStack()); + + __asan_disable_fake_stack(); + assert(IsOnStack()); + + __asan_enable_fake_stack(); + assert(IsOnStack()); + + return 0; +} From 7296b02aae1022414296abbceea5b1d92620402c Mon Sep 17 00:00:00 2001 From: Wiktor Garbacz Date: Tue, 25 Nov 2025 16:18:10 +0100 Subject: [PATCH 09/12] Rename the functions & use counter --- compiler-rt/include/sanitizer/asan_interface.h | 9 +++++---- compiler-rt/lib/asan/asan_fake_stack.cpp | 14 +++++++------- compiler-rt/lib/asan/asan_interface.inc | 4 ++-- compiler-rt/lib/asan/asan_thread.cpp | 15 ++++++++++++++- compiler-rt/lib/asan/asan_thread.h | 10 ++++------ compiler-rt/lib/asan_abi/asan_abi.cpp | 4 ++-- compiler-rt/lib/asan_abi/asan_abi.h | 4 ++-- compiler-rt/lib/asan_abi/asan_abi_shim.cpp | 4 ++-- ...ble_fake_stack.cpp => suppress_fake_stack.cpp} | 4 ++-- ...cpp => suppress_fake_stack_force_disabled.cpp} | 6 ++++-- 10 files changed, 44 insertions(+), 30 deletions(-) rename compiler-rt/test/asan/TestCases/{disable_fake_stack.cpp => suppress_fake_stack.cpp} (93%) rename compiler-rt/test/asan/TestCases/{disable_fake_stack_force_disabled.cpp => suppress_fake_stack_force_disabled.cpp} (83%) diff --git a/compiler-rt/include/sanitizer/asan_interface.h b/compiler-rt/include/sanitizer/asan_interface.h index a6e8fcd76348e..544f2e4b32687 100644 --- a/compiler-rt/include/sanitizer/asan_interface.h +++ b/compiler-rt/include/sanitizer/asan_interface.h @@ -333,12 +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. +/// Suppresses fake stack for the current thread. /// Temporarily disables use-after-return detection for current thread. -void SANITIZER_CDECL __asan_disable_fake_stack(void); +void SANITIZER_CDECL __asan_suppress_fake_stack(void); -/// (Re)enables fake stack for the current thread. -void SANITIZER_CDECL __asan_enable_fake_stack(void); +/// Unsupresses fake stack for the current thread. +/// Should be paired with a previous __asan_suppress_fake_stack() call. +void SANITIZER_CDECL __asan_unsuppress_fake_stack(void); #ifdef __cplusplus } // extern "C" diff --git a/compiler-rt/lib/asan/asan_fake_stack.cpp b/compiler-rt/lib/asan/asan_fake_stack.cpp index f3d5f938778b3..af73d31b8a5dc 100644 --- a/compiler-rt/lib/asan/asan_fake_stack.cpp +++ b/compiler-rt/lib/asan/asan_fake_stack.cpp @@ -225,23 +225,23 @@ static void SetTLSFakeStack(FakeStack*) {} void ResetTLSFakeStack() {} #endif // (SANITIZER_LINUX && !SANITIZER_ANDROID) || SANITIZER_FUCHSIA -static void DisableFakeStack() { +static void SuppressFakeStack() { AsanThread* t = GetCurrentThread(); if (t) { - t->SetFakeStackEnabled(false); + t->SuppressFakeStack(); } } -static void EnableFakeStack() { +static void UnsuppressFakeStack() { AsanThread* t = GetCurrentThread(); if (t) { - t->SetFakeStackEnabled(true); + t->UnsuppressFakeStack(); } } static FakeStack* GetFakeStack() { AsanThread* t = GetCurrentThread(); - if (!t || !t->IsFakeStackEnabled()) + if (!t || t->IsFakeStackSuppressed()) return nullptr; return t->get_or_create_fake_stack(); } @@ -378,7 +378,7 @@ void __asan_allocas_unpoison(uptr top, uptr bottom) { } SANITIZER_INTERFACE_ATTRIBUTE -void __asan_disable_fake_stack() { return DisableFakeStack(); } +void __asan_suppress_fake_stack() { return SuppressFakeStack(); } SANITIZER_INTERFACE_ATTRIBUTE -void __asan_enable_fake_stack() { return EnableFakeStack(); } +void __asan_unsuppress_fake_stack() { return UnsuppressFakeStack(); } } // extern "C" diff --git a/compiler-rt/lib/asan/asan_interface.inc b/compiler-rt/lib/asan/asan_interface.inc index 1f128b7720841..b465356b1e443 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) @@ -167,12 +165,14 @@ INTERFACE_FUNCTION(__asan_store4_noabort) INTERFACE_FUNCTION(__asan_store8_noabort) INTERFACE_FUNCTION(__asan_store16_noabort) INTERFACE_FUNCTION(__asan_storeN_noabort) +INTERFACE_FUNCTION(__asan_suppress_fake_stack) INTERFACE_FUNCTION(__asan_unpoison_intra_object_redzone) INTERFACE_FUNCTION(__asan_unpoison_memory_region) INTERFACE_FUNCTION(__asan_unpoison_stack_memory) INTERFACE_FUNCTION(__asan_unregister_globals) INTERFACE_FUNCTION(__asan_unregister_elf_globals) INTERFACE_FUNCTION(__asan_unregister_image_globals) +INTERFACE_FUNCTION(__asan_unsuppress_fake_stack) INTERFACE_FUNCTION(__asan_version_mismatch_check_v8) INTERFACE_FUNCTION(__sanitizer_finish_switch_fiber) INTERFACE_FUNCTION(__sanitizer_print_stack_trace) diff --git a/compiler-rt/lib/asan/asan_thread.cpp b/compiler-rt/lib/asan/asan_thread.cpp index 17836c8c4b404..32ab723e89001 100644 --- a/compiler-rt/lib/asan/asan_thread.cpp +++ b/compiler-rt/lib/asan/asan_thread.cpp @@ -251,7 +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; + fake_stack_suppression_counter_ = 0; atomic_store(&stack_switching_, false, memory_order_release); CHECK_EQ(this->stack_size(), 0U); SetThreadStackAndTls(options); @@ -405,6 +405,19 @@ bool AsanThread::AddrIsInStack(uptr addr) { return addr >= bounds.bottom && addr < bounds.top; } +void AsanThread::SuppressFakeStack() { + ++fake_stack_suppression_counter_; + ResetTLSFakeStack(); +} + +void AsanThread::UnsuppressFakeStack() { + if (fake_stack_suppression_counter_ == 0) { + Report("ERROR: Unmatched call to __asan_unsuppress_fake_stack().\n"); + Die(); + } + --fake_stack_suppression_counter_; +} + static bool ThreadStackContainsAddress(ThreadContextBase *tctx_base, void *addr) { AsanThreadContext *tctx = static_cast(tctx_base); diff --git a/compiler-rt/lib/asan/asan_thread.h b/compiler-rt/lib/asan/asan_thread.h index 1c951b757ba00..4a863bd89055b 100644 --- a/compiler-rt/lib/asan/asan_thread.h +++ b/compiler-rt/lib/asan/asan_thread.h @@ -144,11 +144,9 @@ class AsanThread { GetStartData(&data, sizeof(data)); } - bool IsFakeStackEnabled() const { return fake_stack_enabled_; } - void SetFakeStackEnabled(bool enabled) { - fake_stack_enabled_ = enabled; - ResetTLSFakeStack(); - } + bool IsFakeStackSuppressed() const { return fake_stack_suppression_counter_ > 0; } + void SuppressFakeStack(); + void UnsuppressFakeStack(); private: // NOTE: There is no AsanThread constructor. It is allocated @@ -185,7 +183,7 @@ class AsanThread { DTLS *dtls_; FakeStack *fake_stack_; - bool fake_stack_enabled_; + int fake_stack_suppression_counter_; 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..6199bbed09dfc 100644 --- a/compiler-rt/lib/asan_abi/asan_abi.cpp +++ b/compiler-rt/lib/asan_abi/asan_abi.cpp @@ -73,8 +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) {} +void __asan_abi_suppress_fake_stack(void) {} +void __asan_abi_unsuppress_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..cb59976c8506c 100644 --- a/compiler-rt/lib/asan_abi/asan_abi.h +++ b/compiler-rt/lib/asan_abi/asan_abi.h @@ -76,8 +76,8 @@ 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(); +void *__asan_abi_suppress_fake_stack(); +void *__asan_abi_unsuppress_fake_stack(); // 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_shim.cpp b/compiler-rt/lib/asan_abi/asan_abi_shim.cpp index eea415294ca77..66d2ada45fe70 100644 --- a/compiler-rt/lib/asan_abi/asan_abi_shim.cpp +++ b/compiler-rt/lib/asan_abi/asan_abi_shim.cpp @@ -365,8 +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(); } +void __asan_suppress_fake_stack(void) { return __asan_abi_suppress_fake_stack(); } +void __asan_unsuppress_fake_stack(void) { return __asan_abi_unsuppress_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/suppress_fake_stack.cpp similarity index 93% rename from compiler-rt/test/asan/TestCases/disable_fake_stack.cpp rename to compiler-rt/test/asan/TestCases/suppress_fake_stack.cpp index 5bfc98314703f..c9c1401c59cd9 100644 --- a/compiler-rt/test/asan/TestCases/disable_fake_stack.cpp +++ b/compiler-rt/test/asan/TestCases/suppress_fake_stack.cpp @@ -24,10 +24,10 @@ ATTRIBUTE_NOINLINE bool IsOnStack() { int main(int argc, char *argv[]) { assert(!IsOnStack()); - __asan_disable_fake_stack(); + __asan_suppress_fake_stack(); assert(IsOnStack()); - __asan_enable_fake_stack(); + __asan_unsuppress_fake_stack(); assert(!IsOnStack()); return 0; diff --git a/compiler-rt/test/asan/TestCases/disable_fake_stack_force_disabled.cpp b/compiler-rt/test/asan/TestCases/suppress_fake_stack_force_disabled.cpp similarity index 83% rename from compiler-rt/test/asan/TestCases/disable_fake_stack_force_disabled.cpp rename to compiler-rt/test/asan/TestCases/suppress_fake_stack_force_disabled.cpp index 91f37e59abff4..34d31de01c113 100644 --- a/compiler-rt/test/asan/TestCases/disable_fake_stack_force_disabled.cpp +++ b/compiler-rt/test/asan/TestCases/suppress_fake_stack_force_disabled.cpp @@ -1,3 +1,5 @@ +// Check unsuppressing fake stack does not reenable it if disabled via compile or runtime options. +// // RUN: %clangxx_asan %s -mllvm -asan-use-after-return=never -o %t && %run %t // RUN: %clangxx_asan %s -mllvm -asan-use-after-return=runtime -o %t && env ASAN_OPTIONS=detect_stack_use_after_return=0 %run %t @@ -23,10 +25,10 @@ ATTRIBUTE_NOINLINE bool IsOnStack() { int main(int argc, char *argv[]) { assert(IsOnStack()); - __asan_disable_fake_stack(); + __asan_suppress_fake_stack(); assert(IsOnStack()); - __asan_enable_fake_stack(); + __asan_unsuppress_fake_stack(); assert(IsOnStack()); return 0; From 423730616ade1d80cb75a098dc4b9cff1fb21b38 Mon Sep 17 00:00:00 2001 From: Wiktor Garbacz Date: Tue, 25 Nov 2025 16:33:52 +0100 Subject: [PATCH 10/12] Code formatting --- compiler-rt/lib/asan/asan_thread.h | 4 +++- compiler-rt/lib/asan_abi/asan_abi_shim.cpp | 8 ++++++-- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/compiler-rt/lib/asan/asan_thread.h b/compiler-rt/lib/asan/asan_thread.h index 4a863bd89055b..e9ca6b6a59016 100644 --- a/compiler-rt/lib/asan/asan_thread.h +++ b/compiler-rt/lib/asan/asan_thread.h @@ -144,7 +144,9 @@ class AsanThread { GetStartData(&data, sizeof(data)); } - bool IsFakeStackSuppressed() const { return fake_stack_suppression_counter_ > 0; } + bool IsFakeStackSuppressed() const { + return fake_stack_suppression_counter_ > 0; + } void SuppressFakeStack(); void UnsuppressFakeStack(); diff --git a/compiler-rt/lib/asan_abi/asan_abi_shim.cpp b/compiler-rt/lib/asan_abi/asan_abi_shim.cpp index 66d2ada45fe70..7ae7e77aea4a2 100644 --- a/compiler-rt/lib/asan_abi/asan_abi_shim.cpp +++ b/compiler-rt/lib/asan_abi/asan_abi_shim.cpp @@ -365,8 +365,12 @@ 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_suppress_fake_stack(void) { return __asan_abi_suppress_fake_stack(); } -void __asan_unsuppress_fake_stack(void) { return __asan_abi_unsuppress_fake_stack(); } +void __asan_suppress_fake_stack(void) { + return __asan_abi_suppress_fake_stack(); +} +void __asan_unsuppress_fake_stack(void) { + return __asan_abi_unsuppress_fake_stack(); +} // Functions concerning poisoning and unpoisoning fake stack alloca void __asan_alloca_poison(uptr addr, uptr size) { From 5f658bff07ea47426d67d6f2cb6f1028643115cc Mon Sep 17 00:00:00 2001 From: Wiktor Garbacz Date: Wed, 26 Nov 2025 10:19:09 +0100 Subject: [PATCH 11/12] Rename test utility & try to fix it for Windows --- .../test/asan/TestCases/suppress_fake_stack.cpp | 17 +++++++++++------ .../suppress_fake_stack_force_disabled.cpp | 17 +++++++++++------ 2 files changed, 22 insertions(+), 12 deletions(-) diff --git a/compiler-rt/test/asan/TestCases/suppress_fake_stack.cpp b/compiler-rt/test/asan/TestCases/suppress_fake_stack.cpp index c9c1401c59cd9..f5131c819df3e 100644 --- a/compiler-rt/test/asan/TestCases/suppress_fake_stack.cpp +++ b/compiler-rt/test/asan/TestCases/suppress_fake_stack.cpp @@ -9,26 +9,31 @@ volatile uintptr_t saved; -ATTRIBUTE_NOINLINE bool IsOnRealStack(uintptr_t caller_frame) { +ATTRIBUTE_NOINLINE bool IsOnRealStack(uintptr_t parent_frame, + uintptr_t var_addr) { uintptr_t this_frame = reinterpret_cast(__builtin_frame_address(0)); - return this_frame <= saved && saved <= caller_frame; + return this_frame <= var_addr && var_addr <= parent_frame; } -ATTRIBUTE_NOINLINE bool IsOnStack() { +ATTRIBUTE_NOINLINE bool IsOnRealStack(uintptr_t parent_frame) { volatile char temp = ' '; saved = reinterpret_cast(&temp); + return IsOnRealStack(parent_frame, saved); +} + +ATTRIBUTE_NOINLINE bool IsOnRealStack() { return IsOnRealStack(reinterpret_cast(__builtin_frame_address(0))); } int main(int argc, char *argv[]) { - assert(!IsOnStack()); + assert(!IsOnRealStack()); __asan_suppress_fake_stack(); - assert(IsOnStack()); + assert(IsOnRealStack()); __asan_unsuppress_fake_stack(); - assert(!IsOnStack()); + assert(!IsOnRealStack()); return 0; } diff --git a/compiler-rt/test/asan/TestCases/suppress_fake_stack_force_disabled.cpp b/compiler-rt/test/asan/TestCases/suppress_fake_stack_force_disabled.cpp index 34d31de01c113..c549f08a7f0a8 100644 --- a/compiler-rt/test/asan/TestCases/suppress_fake_stack_force_disabled.cpp +++ b/compiler-rt/test/asan/TestCases/suppress_fake_stack_force_disabled.cpp @@ -10,26 +10,31 @@ volatile uintptr_t saved; -ATTRIBUTE_NOINLINE bool IsOnRealStack(uintptr_t caller_frame) { +ATTRIBUTE_NOINLINE bool IsOnRealStack(uintptr_t parent_frame, + uintptr_t var_addr) { uintptr_t this_frame = reinterpret_cast(__builtin_frame_address(0)); - return this_frame <= saved && saved <= caller_frame; + return this_frame <= var_addr && var_addr <= parent_frame; } -ATTRIBUTE_NOINLINE bool IsOnStack() { +ATTRIBUTE_NOINLINE bool IsOnRealStack(uintptr_t parent_frame) { volatile char temp = ' '; saved = reinterpret_cast(&temp); + return IsOnRealStack(parent_frame, saved); +} + +ATTRIBUTE_NOINLINE bool IsOnRealStack() { return IsOnRealStack(reinterpret_cast(__builtin_frame_address(0))); } int main(int argc, char *argv[]) { - assert(IsOnStack()); + assert(IsOnRealStack()); __asan_suppress_fake_stack(); - assert(IsOnStack()); + assert(IsOnRealStack()); __asan_unsuppress_fake_stack(); - assert(IsOnStack()); + assert(IsOnRealStack()); return 0; } From 32699e3a58392da564273c0edf9466b4eb65c8b6 Mon Sep 17 00:00:00 2001 From: Wiktor Garbacz Date: Wed, 26 Nov 2025 11:37:01 +0100 Subject: [PATCH 12/12] Explicitly set UAR option as those default to false on Windows --- compiler-rt/test/asan/TestCases/suppress_fake_stack.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler-rt/test/asan/TestCases/suppress_fake_stack.cpp b/compiler-rt/test/asan/TestCases/suppress_fake_stack.cpp index f5131c819df3e..f072c6ad3b034 100644 --- a/compiler-rt/test/asan/TestCases/suppress_fake_stack.cpp +++ b/compiler-rt/test/asan/TestCases/suppress_fake_stack.cpp @@ -1,4 +1,4 @@ -// RUN: %clangxx_asan %s -o %t && %run %t +// RUN: %clangxx_asan %s -o %t && env ASAN_OPTIONS=detect_stack_use_after_return=1 %run %t // RUN: %clangxx_asan %s -mllvm -asan-use-after-return=runtime -o %t && env ASAN_OPTIONS=detect_stack_use_after_return=1 %run %t // RUN: %clangxx_asan %s -mllvm -asan-use-after-return=always -o %t && %run %t