[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
diff --git a/lib/asan/asan_fake_stack.cc b/lib/asan/asan_fake_stack.cc
index 624e53b..69044f0 100644
--- a/lib/asan/asan_fake_stack.cc
+++ b/lib/asan/asan_fake_stack.cc
@@ -74,6 +74,7 @@
   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 7daf373..b6dc23b 100644
--- a/lib/asan/asan_fake_stack.h
+++ b/lib/asan/asan_fake_stack.h
@@ -56,9 +56,7 @@
 // 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 64d07ca..5bea433 100644
--- a/lib/asan/asan_thread.cc
+++ b/lib/asan/asan_thread.cc
@@ -107,6 +107,27 @@
   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 a17a7b4..55c3996 100644
--- a/lib/asan/asan_thread.h
+++ b/lib/asan/asan_thread.h
@@ -82,8 +82,8 @@
   }
 
   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 @@
   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 59a2814..70aab4f 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 @@
 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 2d321ba..79dd72c 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 @@
   // 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;
 }