AddressSanitizer run-time library. Not yet integrated with the compiler-rt build system, but can be built using the old makefile. See details in README.txt

git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@145463 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/lib/asan/asan_thread.cc b/lib/asan/asan_thread.cc
new file mode 100644
index 0000000..27fa2fe
--- /dev/null
+++ b/lib/asan/asan_thread.cc
@@ -0,0 +1,139 @@
+//===-- asan_thread.cc ------------------------------------------*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file is a part of AddressSanitizer, an address sanity checker.
+//
+// Thread-related code.
+//===----------------------------------------------------------------------===//
+#include "asan_allocator.h"
+#include "asan_interceptors.h"
+#include "asan_thread.h"
+#include "asan_thread_registry.h"
+#include "asan_mapping.h"
+
+#include <sys/mman.h>
+#include <pthread.h>
+#include <stdlib.h>
+#include <string.h>
+
+namespace __asan {
+
+AsanThread::AsanThread(LinkerInitialized x)
+    : fake_stack_(x),
+      malloc_storage_(x),
+      stats_(x) { }
+
+AsanThread::AsanThread(int parent_tid, void *(*start_routine) (void *),
+                       void *arg, AsanStackTrace *stack)
+    : start_routine_(start_routine),
+      arg_(arg) {
+  asanThreadRegistry().RegisterThread(this, parent_tid, stack);
+}
+
+AsanThread::~AsanThread() {
+  asanThreadRegistry().UnregisterThread(this);
+  fake_stack().Cleanup();
+  // We also clear the shadow on thread destruction because
+  // some code may still be executing in later TSD destructors
+  // and we don't want it to have any poisoned stack.
+  ClearShadowForThreadStack();
+}
+
+void AsanThread::ClearShadowForThreadStack() {
+  uintptr_t shadow_bot = MemToShadow(stack_bottom_);
+  uintptr_t shadow_top = MemToShadow(stack_top_);
+  real_memset((void*)shadow_bot, 0, shadow_top - shadow_bot);
+}
+
+void *AsanThread::ThreadStart() {
+  SetThreadStackTopAndBottom();
+  fake_stack_.Init(stack_size());
+  if (FLAG_v >= 1) {
+    int local = 0;
+    Report("T%d: stack [%p,%p) size 0x%lx; local=%p, pthread_self=%p\n",
+           tid(), stack_bottom_, stack_top_,
+           stack_top_ - stack_bottom_, &local, pthread_self());
+  }
+
+  CHECK(AddrIsInMem(stack_bottom_));
+  CHECK(AddrIsInMem(stack_top_));
+
+  ClearShadowForThreadStack();
+
+  if (!start_routine_) {
+    // start_routine_ == NULL if we're on the main thread or on one of the
+    // OS X libdispatch worker threads. But nobody is supposed to call
+    // ThreadStart() for the worker threads.
+    CHECK(tid() == 0);
+    return 0;
+  }
+
+  void *res = start_routine_(arg_);
+  malloc_storage().CommitBack();
+
+  if (FLAG_v >= 1) {
+    Report("T%d exited\n", tid());
+  }
+
+  return res;
+}
+
+const char *AsanThread::GetFrameNameByAddr(uintptr_t addr, uintptr_t *offset) {
+  uintptr_t bottom = 0;
+  bool is_fake_stack = false;
+  if (AddrIsInStack(addr)) {
+    bottom = stack_bottom();
+  } else {
+    bottom = fake_stack().AddrIsInFakeStack(addr);
+    CHECK(bottom);
+    is_fake_stack = true;
+  }
+  uintptr_t aligned_addr = addr & ~(__WORDSIZE/8 - 1);  // align addr.
+  uintptr_t *ptr = (uintptr_t*)aligned_addr;
+  while (ptr >= (uintptr_t*)bottom) {
+    if (ptr[0] == kCurrentStackFrameMagic ||
+        (is_fake_stack && ptr[0] == kRetiredStackFrameMagic)) {
+      *offset = addr - (uintptr_t)ptr;
+      return (const char*)ptr[1];
+    }
+    ptr--;
+  }
+  *offset = 0;
+  return "UNKNOWN";
+}
+
+void AsanThread::SetThreadStackTopAndBottom() {
+#ifdef __APPLE__
+  size_t stacksize = pthread_get_stacksize_np(pthread_self());
+  void *stackaddr = pthread_get_stackaddr_np(pthread_self());
+  stack_top_ = (uintptr_t)stackaddr;
+  stack_bottom_ = stack_top_ - stacksize;
+  int local;
+  CHECK(AddrIsInStack((uintptr_t)&local));
+#else
+  pthread_attr_t attr;
+  CHECK(pthread_getattr_np(pthread_self(), &attr) == 0);
+  size_t stacksize = 0;
+  void *stackaddr = NULL;
+  pthread_attr_getstack(&attr, &stackaddr, &stacksize);
+  pthread_attr_destroy(&attr);
+
+  stack_top_ = (uintptr_t)stackaddr + stacksize;
+  stack_bottom_ = (uintptr_t)stackaddr;
+  // When running with unlimited stack size, we still want to set some limit.
+  // The unlimited stack size is caused by 'ulimit -s unlimited'.
+  // Also, for some reason, GNU make spawns subrocesses with unlimited stack.
+  if (stacksize > kMaxThreadStackSize) {
+    stack_bottom_ = stack_top_ - kMaxThreadStackSize;
+  }
+  CHECK(AddrIsInStack((uintptr_t)&attr));
+#endif
+}
+
+}  // namespace __asan