[compiler-rt] r182247 - [lsan] Interceptors for standalone LSan.

Sergey Matveev earthdok at google.com
Mon May 20 04:01:40 PDT 2013


Author: smatveev
Date: Mon May 20 06:01:40 2013
New Revision: 182247

URL: http://llvm.org/viewvc/llvm-project?rev=182247&view=rev
Log:
[lsan] Interceptors for standalone LSan.

Added:
    compiler-rt/trunk/lib/lsan/lsan_interceptors.cc

Added: compiler-rt/trunk/lib/lsan/lsan_interceptors.cc
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/lsan/lsan_interceptors.cc?rev=182247&view=auto
==============================================================================
--- compiler-rt/trunk/lib/lsan/lsan_interceptors.cc (added)
+++ compiler-rt/trunk/lib/lsan/lsan_interceptors.cc Mon May 20 06:01:40 2013
@@ -0,0 +1,249 @@
+//=-- lsan_interceptors.cc ------------------------------------------------===//
+//
+//                     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 LeakSanitizer.
+// Interceptors for standalone LSan.
+//
+//===----------------------------------------------------------------------===//
+
+#include "interception/interception.h"
+#include "sanitizer_common/sanitizer_allocator.h"
+#include "sanitizer_common/sanitizer_atomic.h"
+#include "sanitizer_common/sanitizer_common.h"
+#include "sanitizer_common/sanitizer_flags.h"
+#include "sanitizer_common/sanitizer_internal_defs.h"
+#include "sanitizer_common/sanitizer_linux.h"
+#include "sanitizer_common/sanitizer_platform_limits_posix.h"
+#include "lsan.h"
+#include "lsan_allocator.h"
+#include "lsan_thread.h"
+
+using namespace __lsan;
+
+extern "C" {
+int pthread_attr_init(void *attr);
+int pthread_attr_destroy(void *attr);
+int pthread_attr_getdetachstate(void *attr, int *v);
+int pthread_key_create(unsigned *key, void (*destructor)(void* v));
+int pthread_setspecific(unsigned key, const void *v);
+}
+
+#define GET_STACK_TRACE                                                      \
+  StackTrace stack;                                                          \
+  {                                                                          \
+    uptr stack_top = 0, stack_bottom = 0;                                    \
+    ThreadContext *t;                                                        \
+    bool fast = common_flags()->fast_unwind_on_malloc;                       \
+    if (fast && (t = CurrentThreadContext())) {                              \
+      stack_top = t->stack_end();                                            \
+      stack_bottom = t->stack_begin();                                       \
+    }                                                                        \
+    GetStackTrace(&stack, __sanitizer::common_flags()->malloc_context_size,  \
+                  StackTrace::GetCurrentPc(),                                \
+                  GET_CURRENT_FRAME(), stack_top, stack_bottom, fast);       \
+  }
+
+///// Malloc/free interceptors. /////
+
+namespace std {
+  struct nothrow_t;
+}
+
+INTERCEPTOR(void*, malloc, uptr size) {
+  Init();
+  GET_STACK_TRACE;
+  return Allocate(stack, size, 1, false);
+}
+
+INTERCEPTOR(void, free, void *p) {
+  Init();
+  Deallocate(p);
+}
+
+INTERCEPTOR(void*, calloc, uptr nmemb, uptr size) {
+  if (CallocShouldReturnNullDueToOverflow(size, nmemb)) return 0;
+  Init();
+  GET_STACK_TRACE;
+  size *= nmemb;
+  return Allocate(stack, size, 1, true);
+}
+
+INTERCEPTOR(void*, realloc, void *q, uptr size) {
+  Init();
+  GET_STACK_TRACE;
+  return Reallocate(stack, q, size, 1);
+}
+
+INTERCEPTOR(void*, memalign, uptr alignment, uptr size) {
+  Init();
+  GET_STACK_TRACE;
+  return Allocate(stack, size, alignment, false);
+}
+
+INTERCEPTOR(int, posix_memalign, void **memptr, uptr alignment, uptr size) {
+  Init();
+  GET_STACK_TRACE;
+  *memptr = Allocate(stack, size, alignment, false);
+  // FIXME: Return ENOMEM if user requested more than max alloc size.
+  return 0;
+}
+
+INTERCEPTOR(void*, valloc, uptr size) {
+  Init();
+  GET_STACK_TRACE;
+  if (size == 0)
+    size = GetPageSizeCached();
+  return Allocate(stack, size, GetPageSizeCached(), false);
+}
+
+INTERCEPTOR(uptr, malloc_usable_size, void *ptr) {
+  return GetMallocUsableSize(ptr);
+}
+
+struct fake_mallinfo {
+  int x[10];
+};
+
+INTERCEPTOR(struct fake_mallinfo, mallinfo, void) {
+  struct fake_mallinfo res;
+  internal_memset(&res, 0, sizeof(res));
+  return res;
+}
+
+INTERCEPTOR(int, mallopt, int cmd, int value) {
+  return -1;
+}
+
+void *operator new(uptr size) ALIAS("malloc") SANITIZER_INTERFACE_ATTRIBUTE;
+void *operator new[](uptr size) ALIAS("malloc") SANITIZER_INTERFACE_ATTRIBUTE;
+void *operator new(uptr size, std::nothrow_t const&) ALIAS("malloc")
+    SANITIZER_INTERFACE_ATTRIBUTE;
+void *operator new[](uptr size, std::nothrow_t const&) ALIAS("malloc")
+    SANITIZER_INTERFACE_ATTRIBUTE;
+void operator delete(void *ptr) ALIAS("free") SANITIZER_INTERFACE_ATTRIBUTE;
+void operator delete[](void *ptr) ALIAS("free") SANITIZER_INTERFACE_ATTRIBUTE;
+void operator delete(void *ptr, std::nothrow_t const&) ALIAS("free")
+    SANITIZER_INTERFACE_ATTRIBUTE;
+void operator delete[](void *ptr, std::nothrow_t const&) ALIAS("free")
+    SANITIZER_INTERFACE_ATTRIBUTE;
+
+extern "C" {
+void cfree(void *p) ALIAS("free") SANITIZER_INTERFACE_ATTRIBUTE;
+void *pvalloc(uptr size) ALIAS("valloc")
+    SANITIZER_INTERFACE_ATTRIBUTE;
+// We need this to intercept the __libc_memalign calls that are used to
+// allocate dynamic TLS space in ld-linux.so.
+void *__libc_memalign(uptr alignment, uptr size)
+    ALIAS("memalign") SANITIZER_INTERFACE_ATTRIBUTE;
+}
+
+///// Thread initialization and finalization. /////
+
+static unsigned g_thread_finalize_key;
+
+static void thread_finalize(void *v) {
+  uptr iter = (uptr)v;
+  if (iter > 1) {
+    if (pthread_setspecific(g_thread_finalize_key, (void*)(iter - 1))) {
+      Report("LeakSanitizer: failed to set thread key.\n");
+      Die();
+    }
+    return;
+  }
+  ThreadFinish();
+}
+
+struct ThreadParam {
+  void *(*callback)(void *arg);
+  void *param;
+  atomic_uintptr_t tid;
+};
+
+// PTHREAD_DESTRUCTOR_ITERATIONS from glibc.
+const uptr kPthreadDestructorIterations = 4;
+
+extern "C" void *__lsan_thread_start_func(void *arg) {
+  ThreadParam *p = (ThreadParam*)arg;
+  void* (*callback)(void *arg) = p->callback;
+  void *param = p->param;
+  // Wait until the last iteration to maximize the chance that we are the last
+  // destructor to run.
+  if (pthread_setspecific(g_thread_finalize_key,
+                          (void*)kPthreadDestructorIterations)) {
+    Report("LeakSanitizer: failed to set thread key.\n");
+    Die();
+  }
+  int tid = 0;
+  while ((tid = atomic_load(&p->tid, memory_order_acquire)) == 0)
+    internal_sched_yield();
+  atomic_store(&p->tid, 0, memory_order_release);
+  SetCurrentThread(tid);
+  ThreadStart(tid, GetTid());
+  return callback(param);
+}
+
+INTERCEPTOR(int, pthread_create,
+    void *th, void *attr, void *(*callback)(void*), void * param) {
+  __sanitizer_pthread_attr_t myattr;
+  if (attr == 0) {
+    pthread_attr_init(&myattr);
+    attr = &myattr;
+  }
+  AdjustStackSizeLinux(attr, 0);
+  int detached = 0;
+  pthread_attr_getdetachstate(attr, &detached);
+  ThreadParam p;
+  p.callback = callback;
+  p.param = param;
+  atomic_store(&p.tid, 0, memory_order_relaxed);
+  int res = REAL(pthread_create)(th, attr, __lsan_thread_start_func, &p);
+  if (res == 0) {
+    int tid = ThreadCreate(GetCurrentThread(), *(uptr *)th, detached);
+    CHECK_NE(tid, 0);
+    atomic_store(&p.tid, tid, memory_order_release);
+    while (atomic_load(&p.tid, memory_order_acquire) != 0)
+      internal_sched_yield();
+  }
+  if (attr == &myattr)
+    pthread_attr_destroy(&myattr);
+  return res;
+}
+
+INTERCEPTOR(int, pthread_join, void *th, void **ret) {
+  int tid = ThreadTid((uptr)th);
+  int res = REAL(pthread_join)(th, ret);
+  if (res == 0)
+    ThreadJoin(tid);
+  return res;
+}
+
+namespace __lsan {
+
+void InitializeInterceptors() {
+  INTERCEPT_FUNCTION(malloc);
+  INTERCEPT_FUNCTION(free);
+  INTERCEPT_FUNCTION(calloc);
+  INTERCEPT_FUNCTION(realloc);
+  INTERCEPT_FUNCTION(memalign);
+  INTERCEPT_FUNCTION(posix_memalign);
+  INTERCEPT_FUNCTION(memalign);
+  INTERCEPT_FUNCTION(valloc);
+  INTERCEPT_FUNCTION(malloc_usable_size);
+  INTERCEPT_FUNCTION(mallinfo);
+  INTERCEPT_FUNCTION(mallopt);
+  INTERCEPT_FUNCTION(pthread_create);
+  INTERCEPT_FUNCTION(pthread_join);
+
+  if (pthread_key_create(&g_thread_finalize_key, &thread_finalize)) {
+    Report("LeakSanitizer: failed to create thread key.\n");
+    Die();
+  }
+}
+
+}  // namespace __lsan





More information about the llvm-commits mailing list