forked from OSchip/llvm-project
[asan] hopefully make the FakeStack async-signal safe, enable the related test
llvm-svn: 190592
This commit is contained in:
parent
9c0748a90c
commit
628cda7367
|
@ -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);
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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_));
|
||||
|
|
|
@ -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_;
|
||||
|
|
|
@ -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");
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue