diff options
author | Kostya Serebryany <kcc@google.com> | 2013-09-12 08:34:50 +0000 |
---|---|---|
committer | Kostya Serebryany <kcc@google.com> | 2013-09-12 08:34:50 +0000 |
commit | c98fc1f8e52812cfaf5b19a29db5ed56acb0a682 (patch) | |
tree | c90e96b56b5a6a608fe37000297c40afb2bef68e | |
parent | 96a575f05b2a45774170a118ea69ddae3659b645 (diff) |
[asan] hopefully make the FakeStack async-signal safe, enable the related test
git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@190592 91177308-0d34-0410-b5e6-96231b3b80d8
-rw-r--r-- | lib/asan/asan_fake_stack.cc | 1 | ||||
-rw-r--r-- | lib/asan/asan_fake_stack.h | 2 | ||||
-rw-r--r-- | lib/asan/asan_thread.cc | 21 | ||||
-rw-r--r-- | lib/asan/asan_thread.h | 6 | ||||
-rw-r--r-- | lib/asan/lit_tests/TestCases/Linux/uar_signals.cc | 18 | ||||
-rw-r--r-- | lib/asan/lit_tests/TestCases/stack-use-after-return.cc | 24 |
6 files changed, 61 insertions, 11 deletions
diff --git a/lib/asan/asan_fake_stack.cc b/lib/asan/asan_fake_stack.cc index 624e53bda..69044f00c 100644 --- a/lib/asan/asan_fake_stack.cc +++ b/lib/asan/asan_fake_stack.cc @@ -74,6 +74,7 @@ ALWAYS_INLINE uptr OnMalloc(uptr class_id, uptr size, uptr real_stack) { AsanThread *t = GetCurrentThread(); if (!t) return real_stack; FakeStack *fs = t->fake_stack(); + if (!fs) return real_stack; FakeFrame *ff = fs->Allocate(fs->stack_size_log(), class_id, real_stack); uptr ptr = reinterpret_cast<uptr>(ff); PoisonShadow(ptr, size, 0); diff --git a/lib/asan/asan_fake_stack.h b/lib/asan/asan_fake_stack.h index 7daf37388..b6dc23bb9 100644 --- a/lib/asan/asan_fake_stack.h +++ b/lib/asan/asan_fake_stack.h @@ -56,9 +56,7 @@ struct FakeFrame { // frames in round robin fasion to maximize the delay between a deallocation // and the next allocation. // -// FIXME: don't lazy init the FakeStack (not async-signal safe). // FIXME: handle throw/longjmp/clone, i.e. garbage collect the unwinded frames. -// FIXME: use low bits of the pointer to store stack_size_log_ (performance). class FakeStack { static const uptr kMinStackFrameSizeLog = 6; // Min frame is 64B. static const uptr kMaxStackFrameSizeLog = 16; // Max stack frame is 64K. diff --git a/lib/asan/asan_thread.cc b/lib/asan/asan_thread.cc index 64d07ca0d..5bea433fb 100644 --- a/lib/asan/asan_thread.cc +++ b/lib/asan/asan_thread.cc @@ -107,6 +107,27 @@ void AsanThread::Destroy() { UnmapOrDie(this, size); } +// We want to create the FakeStack lazyly on the first use, but not eralier +// than the stack size is known and the procedure has to be async-signal safe. +FakeStack *AsanThread::AsyncSignalSafeLazyInitFakeStack() { + uptr stack_size = this->stack_size(); + if (stack_size == 0) // stack_size is not yet available, don't use FakeStack. + return 0; + uptr old_val = 0; + // fake_stack_ has 3 states: + // 0 -- not initialized + // 1 -- being initialized + // ptr -- initialized + // This CAS checks if the state was 0 and if so changes it to state 1, + // if that was successfull, it initilizes the pointer. + if (atomic_compare_exchange_strong( + reinterpret_cast<atomic_uintptr_t *>(&fake_stack_), &old_val, 1UL, + memory_order_relaxed)) + return fake_stack_ = + FakeStack::Create(Log2(RoundUpToPowerOfTwo(stack_size))); + return 0; +} + void AsanThread::Init() { SetThreadStackAndTls(); CHECK(AddrIsInMem(stack_bottom_)); diff --git a/lib/asan/asan_thread.h b/lib/asan/asan_thread.h index a17a7b4dd..55c399661 100644 --- a/lib/asan/asan_thread.h +++ b/lib/asan/asan_thread.h @@ -82,8 +82,8 @@ class AsanThread { } FakeStack *fake_stack() { - if (!fake_stack_) // FIXME: lazy init is not async-signal safe. - fake_stack_ = FakeStack::Create(Log2(RoundUpToPowerOfTwo(stack_size()))); + if (reinterpret_cast<uptr>(fake_stack_) <= 1) + return AsyncSignalSafeLazyInitFakeStack(); return fake_stack_; } @@ -100,6 +100,8 @@ class AsanThread { AsanThread() : unwinding(false) {} void SetThreadStackAndTls(); void ClearShadowForThreadStackAndTLS(); + FakeStack *AsyncSignalSafeLazyInitFakeStack(); + AsanThreadContext *context_; thread_callback_t start_routine_; void *arg_; diff --git a/lib/asan/lit_tests/TestCases/Linux/uar_signals.cc b/lib/asan/lit_tests/TestCases/Linux/uar_signals.cc index 59a281487..70aab4fef 100644 --- a/lib/asan/lit_tests/TestCases/Linux/uar_signals.cc +++ b/lib/asan/lit_tests/TestCases/Linux/uar_signals.cc @@ -1,7 +1,7 @@ // This test shows that the current implementation of use-after-return is // not signal-safe. // RUN: %clangxx_asan -O1 %s -o %t -lpthread && %t -// FAILS: %clangxx_asan -fsanitize=use-after-return -O1 %s -o %t -lpthread&& %t +// RUN: %clangxx_asan -fsanitize=use-after-return -O1 %s -o %t -lpthread && %t #include <signal.h> #include <stdlib.h> #include <stdio.h> @@ -57,10 +57,14 @@ void *Thread(void *) { int main(int argc, char **argv) { EnableSigprof(SignalHandler); - const int kNumThread = 32; - pthread_t t[kNumThread]; - for (int i = 0; i < kNumThread; i++) - pthread_create(&t[i], 0, Thread, 0); - for (int i = 0; i < kNumThread; i++) - pthread_join(t[i], 0); + for (int i = 0; i < 4; i++) { + fprintf(stderr, "."); + const int kNumThread = sizeof(void*) == 8 ? 16 : 8; + pthread_t t[kNumThread]; + for (int i = 0; i < kNumThread; i++) + pthread_create(&t[i], 0, Thread, 0); + for (int i = 0; i < kNumThread; i++) + pthread_join(t[i], 0); + } + fprintf(stderr, "\n"); } diff --git a/lib/asan/lit_tests/TestCases/stack-use-after-return.cc b/lib/asan/lit_tests/TestCases/stack-use-after-return.cc index 2d321ba6f..79dd72c6a 100644 --- a/lib/asan/lit_tests/TestCases/stack-use-after-return.cc +++ b/lib/asan/lit_tests/TestCases/stack-use-after-return.cc @@ -9,13 +9,22 @@ // Regression test for a CHECK failure with small stack size and large frame. // RUN: %clangxx_asan -fsanitize=use-after-return -O3 %s -o %t -DkSize=10000 && \ // RUN: (ulimit -s 65; not %t) 2>&1 | FileCheck %s +// +// Test that we can find UAR in a thread other than main: +// RUN: %clangxx_asan -fsanitize=use-after-return -DUseThread -O2 %s -o %t && \ +// RUN: not %t 2>&1 | FileCheck --check-prefix=THREAD %s #include <stdio.h> +#include <pthread.h> #ifndef kSize # define kSize 1 #endif +#ifndef UseThread +# define UseThread 0 +#endif + __attribute__((noinline)) char *Ident(char *x) { fprintf(stderr, "1: %p\n", x); @@ -36,9 +45,24 @@ void Func2(char *x) { // CHECK: #0{{.*}}Func2{{.*}}stack-use-after-return.cc:[[@LINE-2]] // CHECK: is located in stack of thread T0 at offset // CHECK: 'local' <== Memory access at offset 32 is inside this variable + // THREAD: WRITE of size 1 {{.*}} thread T{{[1-9]}} + // THREAD: #0{{.*}}Func2{{.*}}stack-use-after-return.cc:[[@LINE-6]] + // THREAD: is located in stack of thread T{{[1-9]}} at offset + // THREAD: 'local' <== Memory access at offset 32 is inside this variable +} + +void *Thread(void *unused) { + Func2(Func1()); + return NULL; } int main(int argc, char **argv) { +#if UseThread + pthread_t t; + pthread_create(&t, 0, Thread, 0); + pthread_join(t, 0); +#else Func2(Func1()); +#endif return 0; } |