[compiler-rt] r191897 - tsan: ignore interceptors coming from specified libraries

Dmitry Vyukov dvyukov at google.com
Thu Oct 3 06:37:18 PDT 2013


Author: dvyukov
Date: Thu Oct  3 08:37:17 2013
New Revision: 191897

URL: http://llvm.org/viewvc/llvm-project?rev=191897&view=rev
Log:
tsan: ignore interceptors coming from specified libraries

LibIgnore allows to ignore all interceptors called from a particular set
of dynamic libraries. LibIgnore remembers all "called_from_lib" suppressions
from the provided SuppressionContext; finds code ranges for the libraries;
and checks whether the provided PC value belongs to the code ranges.

Also make malloc and friends interceptors use SCOPED_INTERCEPTOR_RAW instead of
SCOPED_TSAN_INTERCEPTOR, because if they are called from an ignored lib,
then must call our internal allocator instead of libc malloc.


Added:
    compiler-rt/trunk/lib/sanitizer_common/sanitizer_libignore.cc
    compiler-rt/trunk/lib/sanitizer_common/sanitizer_libignore.h
    compiler-rt/trunk/lib/tsan/lit_tests/ignore_lib0.cc
    compiler-rt/trunk/lib/tsan/lit_tests/ignore_lib0.cc.supp
    compiler-rt/trunk/lib/tsan/lit_tests/ignore_lib1.cc
    compiler-rt/trunk/lib/tsan/lit_tests/ignore_lib1.cc.supp
    compiler-rt/trunk/lib/tsan/lit_tests/ignore_lib2.cc
    compiler-rt/trunk/lib/tsan/lit_tests/ignore_lib2.cc.supp
    compiler-rt/trunk/lib/tsan/lit_tests/ignore_lib3.cc
    compiler-rt/trunk/lib/tsan/lit_tests/ignore_lib3.cc.supp
    compiler-rt/trunk/lib/tsan/lit_tests/ignore_lib_lib.h
Modified:
    compiler-rt/trunk/lib/sanitizer_common/CMakeLists.txt
    compiler-rt/trunk/lib/sanitizer_common/sanitizer_suppressions.cc
    compiler-rt/trunk/lib/sanitizer_common/sanitizer_suppressions.h
    compiler-rt/trunk/lib/sanitizer_common/tests/sanitizer_suppressions_test.cc
    compiler-rt/trunk/lib/tsan/lit_tests/java_alloc.cc
    compiler-rt/trunk/lib/tsan/lit_tests/java_lock.cc
    compiler-rt/trunk/lib/tsan/rtl/tsan_interceptors.cc
    compiler-rt/trunk/lib/tsan/rtl/tsan_interface_java.cc
    compiler-rt/trunk/lib/tsan/rtl/tsan_interface_java.h
    compiler-rt/trunk/lib/tsan/rtl/tsan_rtl.cc
    compiler-rt/trunk/lib/tsan/rtl/tsan_rtl.h
    compiler-rt/trunk/lib/tsan/rtl/tsan_stat.cc
    compiler-rt/trunk/lib/tsan/rtl/tsan_stat.h
    compiler-rt/trunk/lib/tsan/rtl/tsan_suppressions.cc
    compiler-rt/trunk/lib/tsan/rtl/tsan_suppressions.h

Modified: compiler-rt/trunk/lib/sanitizer_common/CMakeLists.txt
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/sanitizer_common/CMakeLists.txt?rev=191897&r1=191896&r2=191897&view=diff
==============================================================================
--- compiler-rt/trunk/lib/sanitizer_common/CMakeLists.txt (original)
+++ compiler-rt/trunk/lib/sanitizer_common/CMakeLists.txt Thu Oct  3 08:37:17 2013
@@ -6,6 +6,7 @@ set(SANITIZER_SOURCES
   sanitizer_common.cc
   sanitizer_flags.cc
   sanitizer_libc.cc
+  sanitizer_libignore.cc
   sanitizer_linux.cc
   sanitizer_mac.cc
   sanitizer_platform_limits_linux.cc
@@ -44,6 +45,7 @@ set(SANITIZER_HEADERS
   sanitizer_internal_defs.h
   sanitizer_lfstack.h
   sanitizer_libc.h
+  sanitizer_libignore.h
   sanitizer_linux.h
   sanitizer_list.h
   sanitizer_mutex.h

Added: compiler-rt/trunk/lib/sanitizer_common/sanitizer_libignore.cc
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/sanitizer_common/sanitizer_libignore.cc?rev=191897&view=auto
==============================================================================
--- compiler-rt/trunk/lib/sanitizer_common/sanitizer_libignore.cc (added)
+++ compiler-rt/trunk/lib/sanitizer_common/sanitizer_libignore.cc Thu Oct  3 08:37:17 2013
@@ -0,0 +1,85 @@
+//===-- sanitizer_libignore.cc --------------------------------------------===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "sanitizer_platform.h"
+#if SANITIZER_LINUX
+
+#include "sanitizer_libignore.h"
+#include "sanitizer_procmaps.h"
+
+namespace __sanitizer {
+
+LibIgnore::LibIgnore(LinkerInitialized) {
+}
+
+void LibIgnore::Init(const SuppressionContext &supp) {
+  BlockingMutexLock lock(&mutex_);
+  CHECK_EQ(count_, 0);
+  const uptr n = supp.SuppressionCount();
+  for (uptr i = 0; i < n; i++) {
+    const Suppression *s = supp.SuppressionAt(i);
+    if (s->type != SuppressionLib)
+      continue;
+    if (count_ >= kMaxLibs) {
+      Report("%s: too many called_from_lib suppressions (max: %d)\n",
+             SanitizerToolName, kMaxLibs);
+      Die();
+    }
+    Lib *lib = &libs_[count_++];
+    lib->templ = internal_strdup(s->templ);
+    lib->name = 0;
+    lib->loaded = false;
+  }
+}
+
+void LibIgnore::OnLibraryLoaded() {
+  BlockingMutexLock lock(&mutex_);
+  MemoryMappingLayout proc_maps(/*cache_enabled*/false);
+  InternalScopedBuffer<char> fn(4096);
+  for (uptr i = 0; i < count_; i++) {
+    Lib *lib = &libs_[i];
+    bool loaded = false;
+    proc_maps.Reset();
+    uptr b, e, off, prot;
+    while (proc_maps.Next(&b, &e, &off, fn.data(), fn.size(), &prot)) {
+      if ((prot & MemoryMappingLayout::kProtectionExecute) != 0 &&
+          TemplateMatch(lib->templ, fn.data())) {
+        if (loaded) {
+          Report("%s: called_from_lib suppression '%s' is matched against"
+                 " 2 libraries: '%s' and '%s'\n",
+                 SanitizerToolName, lib->templ, lib->name, fn.data());
+          Die();
+        }
+        loaded = true;
+        if (!lib->loaded) {
+          lib->loaded = true;
+          lib->name = internal_strdup(fn.data());
+          const uptr idx = atomic_load(&loaded_count_, memory_order_relaxed);
+          code_ranges_[idx].begin = b;
+          code_ranges_[idx].end = e;
+          atomic_store(&loaded_count_, idx + 1, memory_order_release);
+        }
+      }
+    }
+    if (lib->loaded && !loaded) {
+      Report("%s: library '%s' that was matched against called_from_lib"
+             " suppression '%s' is unloaded\n",
+             SanitizerToolName, lib->name, lib->templ);
+      Die();
+    }
+  }
+}
+
+void LibIgnore::OnLibraryUnloaded() {
+  OnLibraryLoaded();
+}
+
+}  // namespace __sanitizer
+
+#endif  // #if SANITIZER_LINUX

Added: compiler-rt/trunk/lib/sanitizer_common/sanitizer_libignore.h
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/sanitizer_common/sanitizer_libignore.h?rev=191897&view=auto
==============================================================================
--- compiler-rt/trunk/lib/sanitizer_common/sanitizer_libignore.h (added)
+++ compiler-rt/trunk/lib/sanitizer_common/sanitizer_libignore.h Thu Oct  3 08:37:17 2013
@@ -0,0 +1,83 @@
+//===-- sanitizer_libignore.h -----------------------------------*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// LibIgnore allows to ignore all interceptors called from a particular set
+// of dynamic libraries. LibIgnore remembers all "called_from_lib" suppressions
+// from the provided SuppressionContext; finds code ranges for the libraries;
+// and checks whether the provided PC value belongs to the code ranges.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef SANITIZER_LIBIGNORE_H
+#define SANITIZER_LIBIGNORE_H
+
+#include "sanitizer_internal_defs.h"
+#include "sanitizer_common.h"
+#include "sanitizer_suppressions.h"
+#include "sanitizer_atomic.h"
+#include "sanitizer_mutex.h"
+
+namespace __sanitizer {
+
+class LibIgnore {
+ public:
+  explicit LibIgnore(LinkerInitialized);
+
+  // Fetches all "called_from_lib" suppressions from the SuppressionContext.
+  void Init(const SuppressionContext &supp);
+
+  // Must be called after a new dynamic library is loaded.
+  void OnLibraryLoaded();
+
+  // Must be called after a dynamic library is unloaded.
+  void OnLibraryUnloaded();
+
+  // Checks whether the provided PC belongs to one of the ignored libraries.
+  bool IsIgnored(uptr pc) const;
+
+ private:
+  struct Lib {
+    char *templ;
+    char *name;
+    bool loaded;
+  };
+
+  struct LibCodeRange {
+    uptr begin;
+    uptr end;
+  };
+
+  static const uptr kMaxLibs = 128;
+
+  // Hot part:
+  atomic_uintptr_t loaded_count_;
+  LibCodeRange code_ranges_[kMaxLibs];
+
+  // Cold part:
+  BlockingMutex mutex_;
+  uptr count_;
+  Lib libs_[kMaxLibs];
+
+  // Disallow copying of LibIgnore objects.
+  LibIgnore(const LibIgnore&);  // not implemented
+  void operator = (const LibIgnore&);  // not implemented
+};
+
+inline bool LibIgnore::IsIgnored(uptr pc) const {
+  const uptr n = atomic_load(&loaded_count_, memory_order_acquire);
+  for (uptr i = 0; i < n; i++) {
+    if (pc >= code_ranges_[i].begin && pc < code_ranges_[i].end)
+      return true;
+  }
+  return false;
+}
+
+}  // namespace __sanitizer
+
+#endif  // SANITIZER_LIBIGNORE_H

Modified: compiler-rt/trunk/lib/sanitizer_common/sanitizer_suppressions.cc
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/sanitizer_common/sanitizer_suppressions.cc?rev=191897&r1=191896&r2=191897&view=diff
==============================================================================
--- compiler-rt/trunk/lib/sanitizer_common/sanitizer_suppressions.cc (original)
+++ compiler-rt/trunk/lib/sanitizer_common/sanitizer_suppressions.cc Thu Oct  3 08:37:17 2013
@@ -20,7 +20,7 @@
 namespace __sanitizer {
 
 static const char *const kTypeStrings[SuppressionTypeCount] = {
-  "none", "race", "mutex", "thread", "signal", "leak"
+  "none", "race", "mutex", "thread", "signal", "leak", "called_from_lib"
 };
 
 bool TemplateMatch(char *templ, const char *str) {
@@ -129,10 +129,15 @@ void SuppressionContext::Parse(const cha
   }
 }
 
-uptr SuppressionContext::SuppressionCount() {
+uptr SuppressionContext::SuppressionCount() const {
   return suppressions_.size();
 }
 
+const Suppression *SuppressionContext::SuppressionAt(uptr i) const {
+  CHECK_LT(i, suppressions_.size());
+  return &suppressions_[i];
+}
+
 void SuppressionContext::GetMatched(
     InternalMmapVector<Suppression *> *matched) {
   for (uptr i = 0; i < suppressions_.size(); i++)

Modified: compiler-rt/trunk/lib/sanitizer_common/sanitizer_suppressions.h
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/sanitizer_common/sanitizer_suppressions.h?rev=191897&r1=191896&r2=191897&view=diff
==============================================================================
--- compiler-rt/trunk/lib/sanitizer_common/sanitizer_suppressions.h (original)
+++ compiler-rt/trunk/lib/sanitizer_common/sanitizer_suppressions.h Thu Oct  3 08:37:17 2013
@@ -25,6 +25,7 @@ enum SuppressionType {
   SuppressionThread,
   SuppressionSignal,
   SuppressionLeak,
+  SuppressionLib,
   SuppressionTypeCount
 };
 
@@ -40,7 +41,8 @@ class SuppressionContext {
   SuppressionContext() : suppressions_(1), can_parse_(true) {}
   void Parse(const char *str);
   bool Match(const char* str, SuppressionType type, Suppression **s);
-  uptr SuppressionCount();
+  uptr SuppressionCount() const;
+  const Suppression *SuppressionAt(uptr i) const;
   void GetMatched(InternalMmapVector<Suppression *> *matched);
 
  private:
@@ -52,7 +54,6 @@ class SuppressionContext {
 
 const char *SuppressionTypeString(SuppressionType t);
 
-// Exposed for testing.
 bool TemplateMatch(char *templ, const char *str);
 
 }  // namespace __sanitizer

Modified: compiler-rt/trunk/lib/sanitizer_common/tests/sanitizer_suppressions_test.cc
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/sanitizer_common/tests/sanitizer_suppressions_test.cc?rev=191897&r1=191896&r2=191897&view=diff
==============================================================================
--- compiler-rt/trunk/lib/sanitizer_common/tests/sanitizer_suppressions_test.cc (original)
+++ compiler-rt/trunk/lib/sanitizer_common/tests/sanitizer_suppressions_test.cc Thu Oct  3 08:37:17 2013
@@ -65,8 +65,10 @@ TEST(Suppressions, TypeStrings) {
   CHECK(!internal_strcmp(SuppressionTypeString(SuppressionThread), "thread"));
   CHECK(!internal_strcmp(SuppressionTypeString(SuppressionSignal), "signal"));
   CHECK(!internal_strcmp(SuppressionTypeString(SuppressionLeak), "leak"));
+  CHECK(!internal_strcmp(SuppressionTypeString(SuppressionLib),
+      "called_from_lib"));
   // Ensure this test is up-to-date when suppression types are added.
-  CHECK_EQ(SuppressionTypeCount, 6);
+  CHECK_EQ(SuppressionTypeCount, 7);
 }
 
 class SuppressionContextTest : public ::testing::Test {

Added: compiler-rt/trunk/lib/tsan/lit_tests/ignore_lib0.cc
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/tsan/lit_tests/ignore_lib0.cc?rev=191897&view=auto
==============================================================================
--- compiler-rt/trunk/lib/tsan/lit_tests/ignore_lib0.cc (added)
+++ compiler-rt/trunk/lib/tsan/lit_tests/ignore_lib0.cc Thu Oct  3 08:37:17 2013
@@ -0,0 +1,30 @@
+// RUN: %clangxx_tsan -O1 %s -DLIB -fPIC -fno-sanitize=thread -shared -o %T/libignore_lib0.so
+// RUN: %clangxx_tsan -O1 %s -L%T -lignore_lib0 -o %t
+// RUN: echo running w/o suppressions:
+// RUN: LD_LIBRARY_PATH=%T not %t 2>&1 | FileCheck %s --check-prefix=CHECK-NOSUPP
+// RUN: echo running with suppressions:
+// RUN: LD_LIBRARY_PATH=%T TSAN_OPTIONS="$TSAN_OPTIONS suppressions=%s.supp" %t 2>&1 | FileCheck %s --check-prefix=CHECK-WITHSUPP
+
+// Tests that interceptors coming from a library specified in called_from_lib
+// suppression are ignored.
+
+#ifndef LIB
+
+extern "C" void libfunc();
+
+int main() {
+  libfunc();
+}
+
+#else  // #ifdef LIB
+
+#include "ignore_lib_lib.h"
+
+#endif  // #ifdef LIB
+
+// CHECK-NOSUPP: WARNING: ThreadSanitizer: data race
+// CHECK-NOSUPP: OK
+
+// CHECK-WITHSUPP-NOT: WARNING: ThreadSanitizer: data race
+// CHECK-WITHSUPP: OK
+

Added: compiler-rt/trunk/lib/tsan/lit_tests/ignore_lib0.cc.supp
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/tsan/lit_tests/ignore_lib0.cc.supp?rev=191897&view=auto
==============================================================================
--- compiler-rt/trunk/lib/tsan/lit_tests/ignore_lib0.cc.supp (added)
+++ compiler-rt/trunk/lib/tsan/lit_tests/ignore_lib0.cc.supp Thu Oct  3 08:37:17 2013
@@ -0,0 +1,2 @@
+called_from_lib:/libignore_lib0.so
+

Added: compiler-rt/trunk/lib/tsan/lit_tests/ignore_lib1.cc
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/tsan/lit_tests/ignore_lib1.cc?rev=191897&view=auto
==============================================================================
--- compiler-rt/trunk/lib/tsan/lit_tests/ignore_lib1.cc (added)
+++ compiler-rt/trunk/lib/tsan/lit_tests/ignore_lib1.cc Thu Oct  3 08:37:17 2013
@@ -0,0 +1,42 @@
+// RUN: %clangxx_tsan -O1 %s -DLIB -fPIC -fno-sanitize=thread -shared -o %T/libignore_lib1.so
+// RUN: %clangxx_tsan -O1 %s -o %t
+// RUN: echo running w/o suppressions:
+// RUN: not %t 2>&1 | FileCheck %s --check-prefix=CHECK-NOSUPP
+// RUN: echo running with suppressions:
+// RUN: TSAN_OPTIONS="$TSAN_OPTIONS suppressions=%s.supp" %t 2>&1 | FileCheck %s --check-prefix=CHECK-WITHSUPP
+
+// Tests that interceptors coming from a dynamically loaded library specified
+// in called_from_lib suppression are ignored.
+
+#ifndef LIB
+
+#include <dlfcn.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <errno.h>
+#include <libgen.h>
+#include <string>
+
+int main(int argc, char **argv) {
+  std::string lib = std::string(dirname(argv[0])) + "/libignore_lib1.so";
+  void *h = dlopen(lib.c_str(), RTLD_GLOBAL | RTLD_NOW);
+  if (h == 0)
+    exit(printf("failed to load the library (%d)\n", errno));
+  void (*f)() = (void(*)())dlsym(h, "libfunc");
+  if (f == 0)
+    exit(printf("failed to find the func (%d)\n", errno));
+  f();
+}
+
+#else  // #ifdef LIB
+
+#include "ignore_lib_lib.h"
+
+#endif  // #ifdef LIB
+
+// CHECK-NOSUPP: WARNING: ThreadSanitizer: data race
+// CHECK-NOSUPP: OK
+
+// CHECK-WITHSUPP-NOT: WARNING: ThreadSanitizer: data race
+// CHECK-WITHSUPP: OK
+

Added: compiler-rt/trunk/lib/tsan/lit_tests/ignore_lib1.cc.supp
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/tsan/lit_tests/ignore_lib1.cc.supp?rev=191897&view=auto
==============================================================================
--- compiler-rt/trunk/lib/tsan/lit_tests/ignore_lib1.cc.supp (added)
+++ compiler-rt/trunk/lib/tsan/lit_tests/ignore_lib1.cc.supp Thu Oct  3 08:37:17 2013
@@ -0,0 +1,2 @@
+called_from_lib:/libignore_lib1.so$
+

Added: compiler-rt/trunk/lib/tsan/lit_tests/ignore_lib2.cc
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/tsan/lit_tests/ignore_lib2.cc?rev=191897&view=auto
==============================================================================
--- compiler-rt/trunk/lib/tsan/lit_tests/ignore_lib2.cc (added)
+++ compiler-rt/trunk/lib/tsan/lit_tests/ignore_lib2.cc Thu Oct  3 08:37:17 2013
@@ -0,0 +1,33 @@
+// RUN: %clangxx_tsan -O1 %s -DLIB -fPIC -fno-sanitize=thread -shared -o %T/libignore_lib2_0.so
+// RUN: %clangxx_tsan -O1 %s -DLIB -fPIC -fno-sanitize=thread -shared -o %T/libignore_lib2_1.so
+// RUN: %clangxx_tsan -O1 %s -o %t
+// RUN: TSAN_OPTIONS="$TSAN_OPTIONS suppressions=%s.supp" not %t 2>&1 | FileCheck %s
+
+// Tests that called_from_lib suppression matched against 2 libraries
+// causes program crash (this is not supported).
+
+#ifndef LIB
+
+#include <dlfcn.h>
+#include <stdio.h>
+#include <libgen.h>
+#include <string>
+
+int main(int argc, char **argv) {
+  std::string lib0 = std::string(dirname(argv[0])) + "/libignore_lib2_0.so";
+  std::string lib1 = std::string(dirname(argv[0])) + "/libignore_lib2_1.so";
+  dlopen(lib0.c_str(), RTLD_GLOBAL | RTLD_NOW);
+  dlopen(lib1.c_str(), RTLD_GLOBAL | RTLD_NOW);
+  fprintf(stderr, "OK\n");
+}
+
+#else  // #ifdef LIB
+
+extern "C" void libfunc() {
+}
+
+#endif  // #ifdef LIB
+
+// CHECK: ThreadSanitizer: called_from_lib suppression 'ignore_lib2' is matched against 2 libraries
+// CHECK-NOT: OK
+

Added: compiler-rt/trunk/lib/tsan/lit_tests/ignore_lib2.cc.supp
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/tsan/lit_tests/ignore_lib2.cc.supp?rev=191897&view=auto
==============================================================================
--- compiler-rt/trunk/lib/tsan/lit_tests/ignore_lib2.cc.supp (added)
+++ compiler-rt/trunk/lib/tsan/lit_tests/ignore_lib2.cc.supp Thu Oct  3 08:37:17 2013
@@ -0,0 +1,2 @@
+called_from_lib:ignore_lib2
+

Added: compiler-rt/trunk/lib/tsan/lit_tests/ignore_lib3.cc
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/tsan/lit_tests/ignore_lib3.cc?rev=191897&view=auto
==============================================================================
--- compiler-rt/trunk/lib/tsan/lit_tests/ignore_lib3.cc (added)
+++ compiler-rt/trunk/lib/tsan/lit_tests/ignore_lib3.cc Thu Oct  3 08:37:17 2013
@@ -0,0 +1,33 @@
+// RUN: %clangxx_tsan -O1 %s -DLIB -fPIC -fno-sanitize=thread -shared -o %T/libignore_lib3.so
+// RUN: %clangxx_tsan -O1 %s -o %t
+// RUN: TSAN_OPTIONS="$TSAN_OPTIONS suppressions=%s.supp" not %t 2>&1 | FileCheck %s
+
+// Tests that unloading of a library matched against called_from_lib suppression
+// causes program crash (this is not supported).
+
+#ifndef LIB
+
+#include <dlfcn.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <errno.h>
+#include <libgen.h>
+#include <string>
+
+int main(int argc, char **argv) {
+  std::string lib = std::string(dirname(argv[0])) + "/libignore_lib3.so";
+  void *h = dlopen(lib.c_str(), RTLD_GLOBAL | RTLD_NOW);
+  dlclose(h);
+  fprintf(stderr, "OK\n");
+}
+
+#else  // #ifdef LIB
+
+extern "C" void libfunc() {
+}
+
+#endif  // #ifdef LIB
+
+// CHECK: ThreadSanitizer: library {{.*}} that was matched against called_from_lib suppression 'ignore_lib3.so' is unloaded
+// CHECK-NOT: OK
+

Added: compiler-rt/trunk/lib/tsan/lit_tests/ignore_lib3.cc.supp
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/tsan/lit_tests/ignore_lib3.cc.supp?rev=191897&view=auto
==============================================================================
--- compiler-rt/trunk/lib/tsan/lit_tests/ignore_lib3.cc.supp (added)
+++ compiler-rt/trunk/lib/tsan/lit_tests/ignore_lib3.cc.supp Thu Oct  3 08:37:17 2013
@@ -0,0 +1,2 @@
+called_from_lib:ignore_lib3.so
+

Added: compiler-rt/trunk/lib/tsan/lit_tests/ignore_lib_lib.h
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/tsan/lit_tests/ignore_lib_lib.h?rev=191897&view=auto
==============================================================================
--- compiler-rt/trunk/lib/tsan/lit_tests/ignore_lib_lib.h (added)
+++ compiler-rt/trunk/lib/tsan/lit_tests/ignore_lib_lib.h Thu Oct  3 08:37:17 2013
@@ -0,0 +1,25 @@
+#include <pthread.h>
+#include <string.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <unistd.h>
+
+void *volatile mem;
+volatile int len;
+
+void *Thread(void *p) {
+  while ((p = __atomic_load_n(&mem, __ATOMIC_ACQUIRE)) == 0)
+    usleep(100);
+  memset(p, 0, len);
+  return 0;
+}
+
+extern "C" void libfunc() {
+  pthread_t t;
+  pthread_create(&t, 0, Thread, 0);
+  len = 10;
+  __atomic_store_n(&mem, malloc(len), __ATOMIC_RELEASE);
+  pthread_join(t, 0);
+  free(mem);
+  fprintf(stderr, "OK\n");
+}

Modified: compiler-rt/trunk/lib/tsan/lit_tests/java_alloc.cc
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/tsan/lit_tests/java_alloc.cc?rev=191897&r1=191896&r2=191897&view=diff
==============================================================================
--- compiler-rt/trunk/lib/tsan/lit_tests/java_alloc.cc (original)
+++ compiler-rt/trunk/lib/tsan/lit_tests/java_alloc.cc Thu Oct  3 08:37:17 2013
@@ -20,7 +20,6 @@ void *Thread(void *p) {
 
 int main() {
   jptr jheap = (jptr)malloc(kHeapSize);
-  __tsan_java_preinit("[vdso]");
   __tsan_java_init(jheap, kHeapSize);
   pthread_t th;
   pthread_create(&th, 0, Thread, (void*)(jheap + kHeapSize / 4));

Modified: compiler-rt/trunk/lib/tsan/lit_tests/java_lock.cc
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/tsan/lit_tests/java_lock.cc?rev=191897&r1=191896&r2=191897&view=diff
==============================================================================
--- compiler-rt/trunk/lib/tsan/lit_tests/java_lock.cc (original)
+++ compiler-rt/trunk/lib/tsan/lit_tests/java_lock.cc Thu Oct  3 08:37:17 2013
@@ -16,7 +16,6 @@ void *Thread(void *p) {
 int main() {
   int const kHeapSize = 1024 * 1024;
   void *jheap = malloc(kHeapSize);
-  __tsan_java_preinit(0);
   __tsan_java_init((jptr)jheap, kHeapSize);
   const int kBlockSize = 16;
   __tsan_java_alloc((jptr)jheap, kBlockSize);

Modified: compiler-rt/trunk/lib/tsan/rtl/tsan_interceptors.cc
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/tsan/rtl/tsan_interceptors.cc?rev=191897&r1=191896&r2=191897&view=diff
==============================================================================
--- compiler-rt/trunk/lib/tsan/rtl/tsan_interceptors.cc (original)
+++ compiler-rt/trunk/lib/tsan/rtl/tsan_interceptors.cc Thu Oct  3 08:37:17 2013
@@ -22,6 +22,7 @@
 #include "interception/interception.h"
 #include "tsan_interface.h"
 #include "tsan_platform.h"
+#include "tsan_suppressions.h"
 #include "tsan_rtl.h"
 #include "tsan_mman.h"
 #include "tsan_fd.h"
@@ -126,18 +127,16 @@ struct SignalContext {
   SignalDesc pending_signals[kSigCount];
 };
 
-// Used to ignore interceptors coming directly from libjvm.so.
-atomic_uintptr_t libjvm_begin;
-atomic_uintptr_t libjvm_end;
-
-static bool libjvm_check(uptr pc) {
-  uptr begin = atomic_load(&libjvm_begin, memory_order_relaxed);
-  if (begin != 0 && pc >= begin) {
-    uptr end = atomic_load(&libjvm_end, memory_order_relaxed);
-    if (end != 0 && pc < end)
-      return true;
-  }
-  return false;
+// The object is 64-byte aligned, because we want hot data to be located in
+// a single cache line if possible (it's accessed in every interceptor).
+static ALIGNED(64) char libignore_placeholder[sizeof(LibIgnore)];
+static LibIgnore *libignore() {
+  return reinterpret_cast<LibIgnore*>(&libignore_placeholder[0]);
+}
+
+void InitializeLibIgnore() {
+  libignore()->Init(*GetSuppressionContext());
+  libignore()->OnLibraryLoaded();
 }
 
 }  // namespace __tsan
@@ -162,12 +161,14 @@ class ScopedInterceptor {
  private:
   ThreadState *const thr_;
   const int in_rtl_;
+  bool in_ignored_lib_;
 };
 
 ScopedInterceptor::ScopedInterceptor(ThreadState *thr, const char *fname,
                                      uptr pc)
     : thr_(thr)
-    , in_rtl_(thr->in_rtl) {
+    , in_rtl_(thr->in_rtl)
+    , in_ignored_lib_(false) {
   if (thr_->in_rtl == 0) {
     Initialize(thr);
     FuncEntry(thr, pc);
@@ -176,9 +177,18 @@ ScopedInterceptor::ScopedInterceptor(Thr
   } else {
     thr_->in_rtl++;
   }
+  if (!thr_->in_ignored_lib && libignore()->IsIgnored(pc)) {
+    in_ignored_lib_ = true;
+    thr_->in_ignored_lib = true;
+    ThreadIgnoreBegin(thr_);
+  }
 }
 
 ScopedInterceptor::~ScopedInterceptor() {
+  if (in_ignored_lib_) {
+    thr_->in_ignored_lib = false;
+    ThreadIgnoreEnd(thr_);
+  }
   thr_->in_rtl--;
   if (thr_->in_rtl == 0) {
     FuncExit(thr_);
@@ -203,7 +213,7 @@ ScopedInterceptor::~ScopedInterceptor()
       Printf("FATAL: ThreadSanitizer: failed to intercept %s\n", #func); \
       Die(); \
     } \
-    if (thr->in_rtl > 1 || libjvm_check(pc)) \
+    if (thr->in_rtl > 1 || thr->in_ignored_lib) \
       return REAL(func)(__VA_ARGS__); \
 /**/
 
@@ -246,6 +256,28 @@ TSAN_INTERCEPTOR(int, nanosleep, void *r
   return res;
 }
 
+TSAN_INTERCEPTOR(void*, dlopen, const char *filename, int flag) {
+  SCOPED_INTERCEPTOR_RAW(dlopen, filename, flag);
+  // dlopen will execute global constructors, so it must be not in rtl.
+  CHECK_EQ(thr->in_rtl, 1);
+  thr->in_rtl = 0;
+  void *res = REAL(dlopen)(filename, flag);
+  thr->in_rtl = 1;
+  libignore()->OnLibraryLoaded();
+  return res;
+}
+
+TSAN_INTERCEPTOR(int, dlclose, void *handle) {
+  SCOPED_INTERCEPTOR_RAW(dlclose, handle);
+  // dlclose will execute global destructors, so it must be not in rtl.
+  CHECK_EQ(thr->in_rtl, 1);
+  thr->in_rtl = 0;
+  int res = REAL(dlclose)(handle);
+  thr->in_rtl = 1;
+  libignore()->OnLibraryUnloaded();
+  return res;
+}
+
 class AtExitContext {
  public:
   AtExitContext()
@@ -441,7 +473,7 @@ TSAN_INTERCEPTOR(void, siglongjmp, uptr
 }
 
 TSAN_INTERCEPTOR(void*, malloc, uptr size) {
-  if (cur_thread()->in_symbolizer || libjvm_check(GET_CALLER_PC()))
+  if (cur_thread()->in_symbolizer)
     return __libc_malloc(size);
   void *p = 0;
   {
@@ -458,7 +490,7 @@ TSAN_INTERCEPTOR(void*, __libc_memalign,
 }
 
 TSAN_INTERCEPTOR(void*, calloc, uptr size, uptr n) {
-  if (cur_thread()->in_symbolizer || libjvm_check(GET_CALLER_PC()))
+  if (cur_thread()->in_symbolizer)
     return __libc_calloc(size, n);
   if (__sanitizer::CallocShouldReturnNullDueToOverflow(size, n))
     return AllocatorReturnNull();
@@ -474,7 +506,7 @@ TSAN_INTERCEPTOR(void*, calloc, uptr siz
 }
 
 TSAN_INTERCEPTOR(void*, realloc, void *p, uptr size) {
-  if (cur_thread()->in_symbolizer || libjvm_check(GET_CALLER_PC()))
+  if (cur_thread()->in_symbolizer)
     return __libc_realloc(p, size);
   if (p)
     invoke_free_hook(p);
@@ -489,7 +521,7 @@ TSAN_INTERCEPTOR(void*, realloc, void *p
 TSAN_INTERCEPTOR(void, free, void *p) {
   if (p == 0)
     return;
-  if (cur_thread()->in_symbolizer || libjvm_check(GET_CALLER_PC()))
+  if (cur_thread()->in_symbolizer)
     return __libc_free(p);
   invoke_free_hook(p);
   SCOPED_INTERCEPTOR_RAW(free, p);
@@ -499,7 +531,7 @@ TSAN_INTERCEPTOR(void, free, void *p) {
 TSAN_INTERCEPTOR(void, cfree, void *p) {
   if (p == 0)
     return;
-  if (cur_thread()->in_symbolizer || libjvm_check(GET_CALLER_PC()))
+  if (cur_thread()->in_symbolizer)
     return __libc_free(p);
   invoke_free_hook(p);
   SCOPED_INTERCEPTOR_RAW(cfree, p);
@@ -508,13 +540,11 @@ TSAN_INTERCEPTOR(void, cfree, void *p) {
 
 TSAN_INTERCEPTOR(uptr, malloc_usable_size, void *p) {
   SCOPED_INTERCEPTOR_RAW(malloc_usable_size, p);
-  if (libjvm_check(pc))
-    return malloc_usable_size(p);
   return user_alloc_usable_size(thr, pc, p);
 }
 
 #define OPERATOR_NEW_BODY(mangled_name) \
-  if (cur_thread()->in_symbolizer || libjvm_check(GET_CALLER_PC())) \
+  if (cur_thread()->in_symbolizer) \
     return __libc_malloc(size); \
   void *p = 0; \
   {  \
@@ -550,7 +580,7 @@ void *operator new[](__sanitizer::uptr s
 
 #define OPERATOR_DELETE_BODY(mangled_name) \
   if (ptr == 0) return;  \
-  if (cur_thread()->in_symbolizer || libjvm_check(GET_CALLER_PC())) \
+  if (cur_thread()->in_symbolizer) \
     return __libc_free(ptr); \
   invoke_free_hook(ptr);  \
   SCOPED_INTERCEPTOR_RAW(mangled_name, ptr);  \
@@ -684,15 +714,6 @@ TSAN_INTERCEPTOR(const char*, strstr, co
 
 TSAN_INTERCEPTOR(char*, strdup, const char *str) {
   SCOPED_TSAN_INTERCEPTOR(strdup, str);
-  if (libjvm_check(pc)) {
-    // The memory must come from libc malloc,
-    // and we must not instrument accesses in this case.
-    uptr n = internal_strlen(str) + 1;
-    void *p = __libc_malloc(n);
-    if (p == 0)
-      return 0;
-    return (char*)internal_memcpy(p, str, n);
-  }
   // strdup will call malloc, so no instrumentation is required here.
   return REAL(strdup)(str);
 }
@@ -747,23 +768,23 @@ TSAN_INTERCEPTOR(int, munmap, void *addr
 }
 
 TSAN_INTERCEPTOR(void*, memalign, uptr align, uptr sz) {
-  SCOPED_TSAN_INTERCEPTOR(memalign, align, sz);
+  SCOPED_INTERCEPTOR_RAW(memalign, align, sz);
   return user_alloc(thr, pc, sz, align);
 }
 
 TSAN_INTERCEPTOR(void*, valloc, uptr sz) {
-  SCOPED_TSAN_INTERCEPTOR(valloc, sz);
+  SCOPED_INTERCEPTOR_RAW(valloc, sz);
   return user_alloc(thr, pc, sz, GetPageSizeCached());
 }
 
 TSAN_INTERCEPTOR(void*, pvalloc, uptr sz) {
-  SCOPED_TSAN_INTERCEPTOR(pvalloc, sz);
+  SCOPED_INTERCEPTOR_RAW(pvalloc, sz);
   sz = RoundUp(sz, GetPageSizeCached());
   return user_alloc(thr, pc, sz, GetPageSizeCached());
 }
 
 TSAN_INTERCEPTOR(int, posix_memalign, void **memptr, uptr align, uptr sz) {
-  SCOPED_TSAN_INTERCEPTOR(posix_memalign, memptr, align, sz);
+  SCOPED_INTERCEPTOR_RAW(posix_memalign, memptr, align, sz);
   *memptr = user_alloc(thr, pc, sz, align);
   return 0;
 }
@@ -852,7 +873,7 @@ extern "C" void *__tsan_thread_start_fun
 
 TSAN_INTERCEPTOR(int, pthread_create,
     void *th, void *attr, void *(*callback)(void*), void * param) {
-  SCOPED_TSAN_INTERCEPTOR(pthread_create, th, attr, callback, param);
+  SCOPED_INTERCEPTOR_RAW(pthread_create, th, attr, callback, param);
   __sanitizer_pthread_attr_t myattr;
   if (attr == 0) {
     pthread_attr_init(&myattr);
@@ -886,7 +907,7 @@ TSAN_INTERCEPTOR(int, pthread_create,
 }
 
 TSAN_INTERCEPTOR(int, pthread_join, void *th, void **ret) {
-  SCOPED_TSAN_INTERCEPTOR(pthread_join, th, ret);
+  SCOPED_INTERCEPTOR_RAW(pthread_join, th, ret);
   int tid = ThreadTid(thr, pc, (uptr)th);
   int res = BLOCK_REAL(pthread_join)(th, ret);
   if (res == 0) {
@@ -1820,7 +1841,7 @@ TSAN_INTERCEPTOR(int, munlockall, void)
 }
 
 TSAN_INTERCEPTOR(int, fork, int fake) {
-  SCOPED_TSAN_INTERCEPTOR(fork, fake);
+  SCOPED_INTERCEPTOR_RAW(fork, fake);
   int pid = REAL(fork)(fake);
   if (pid == 0) {
     // child
@@ -2174,6 +2195,8 @@ void InitializeInterceptors() {
   TSAN_INTERCEPT(munlockall);
 
   TSAN_INTERCEPT(fork);
+  TSAN_INTERCEPT(dlopen);
+  TSAN_INTERCEPT(dlclose);
   TSAN_INTERCEPT(on_exit);
   TSAN_INTERCEPT(__cxa_atexit);
 

Modified: compiler-rt/trunk/lib/tsan/rtl/tsan_interface_java.cc
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/tsan/rtl/tsan_interface_java.cc?rev=191897&r1=191896&r2=191897&view=diff
==============================================================================
--- compiler-rt/trunk/lib/tsan/rtl/tsan_interface_java.cc (original)
+++ compiler-rt/trunk/lib/tsan/rtl/tsan_interface_java.cc Thu Oct  3 08:37:17 2013
@@ -96,8 +96,6 @@ class ScopedJavaFunc {
 
 static u64 jctx_buf[sizeof(JavaContext) / sizeof(u64) + 1];
 static JavaContext *jctx;
-extern atomic_uintptr_t libjvm_begin;
-extern atomic_uintptr_t libjvm_end;
 
 static BlockDesc *getblock(uptr addr) {
   uptr i = (addr - jctx->heap_begin) / kHeapAlignment;
@@ -166,17 +164,6 @@ SyncVar* GetAndRemoveJavaSync(ThreadStat
   ScopedJavaFunc scoped(thr, caller_pc); \
 /**/
 
-void __tsan_java_preinit(const char *libjvm_path) {
-  SCOPED_JAVA_FUNC(__tsan_java_preinit);
-  if (libjvm_path) {
-    uptr begin, end;
-    if (GetCodeRangeForFile(libjvm_path, &begin, &end)) {
-      atomic_store(&libjvm_begin, begin, memory_order_relaxed);
-      atomic_store(&libjvm_end, end, memory_order_relaxed);
-    }
-  }
-}
-
 void __tsan_java_init(jptr heap_begin, jptr heap_size) {
   SCOPED_JAVA_FUNC(__tsan_java_init);
   DPrintf("#%d: java_init(%p, %p)\n", thr->tid, heap_begin, heap_size);

Modified: compiler-rt/trunk/lib/tsan/rtl/tsan_interface_java.h
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/tsan/rtl/tsan_interface_java.h?rev=191897&r1=191896&r2=191897&view=diff
==============================================================================
--- compiler-rt/trunk/lib/tsan/rtl/tsan_interface_java.h (original)
+++ compiler-rt/trunk/lib/tsan/rtl/tsan_interface_java.h Thu Oct  3 08:37:17 2013
@@ -34,11 +34,7 @@ extern "C" {
 
 typedef unsigned long jptr;  // NOLINT
 
-// Must be called before any other callback from Java, right after dlopen
-// of JVM shared lib. If libjvm_path is specified, then all interceptors
-// coming directly from JVM will be ignored.
-void __tsan_java_preinit(const char *libjvm_path) INTERFACE_ATTRIBUTE;
-// Must be called after __tsan_java_preinit but before any other callback.
+// Must be called before any other callback from Java.
 void __tsan_java_init(jptr heap_begin, jptr heap_size) INTERFACE_ATTRIBUTE;
 // Must be called when the application exits.
 // Not necessary the last callback (concurrently running threads are OK).

Modified: compiler-rt/trunk/lib/tsan/rtl/tsan_rtl.cc
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/tsan/rtl/tsan_rtl.cc?rev=191897&r1=191896&r2=191897&view=diff
==============================================================================
--- compiler-rt/trunk/lib/tsan/rtl/tsan_rtl.cc (original)
+++ compiler-rt/trunk/lib/tsan/rtl/tsan_rtl.cc Thu Oct  3 08:37:17 2013
@@ -214,6 +214,7 @@ void Initialize(ThreadState *thr) {
     __sanitizer_set_report_path(flags()->log_path);
   InitializeSuppressions();
 #ifndef TSAN_GO
+  InitializeLibIgnore();
   // Initialize external symbolizer before internal threads are started.
   const char *external_symbolizer = flags()->external_symbolizer_path;
   if (external_symbolizer != 0 && external_symbolizer[0] != '\0') {

Modified: compiler-rt/trunk/lib/tsan/rtl/tsan_rtl.h
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/tsan/rtl/tsan_rtl.h?rev=191897&r1=191896&r2=191897&view=diff
==============================================================================
--- compiler-rt/trunk/lib/tsan/rtl/tsan_rtl.h (original)
+++ compiler-rt/trunk/lib/tsan/rtl/tsan_rtl.h Thu Oct  3 08:37:17 2013
@@ -29,6 +29,7 @@
 #include "sanitizer_common/sanitizer_allocator.h"
 #include "sanitizer_common/sanitizer_allocator_internal.h"
 #include "sanitizer_common/sanitizer_common.h"
+#include "sanitizer_common/sanitizer_libignore.h"
 #include "sanitizer_common/sanitizer_suppressions.h"
 #include "sanitizer_common/sanitizer_thread_registry.h"
 #include "tsan_clock.h"
@@ -434,6 +435,7 @@ struct ThreadState {
   const int unique_id;
   int in_rtl;
   bool in_symbolizer;
+  bool in_ignored_lib;
   bool is_alive;
   bool is_freeing;
   bool is_vptr_access;
@@ -598,6 +600,7 @@ void MapThreadTrace(uptr addr, uptr size
 void DontNeedShadowFor(uptr addr, uptr size);
 void InitializeShadowMemory();
 void InitializeInterceptors();
+void InitializeLibIgnore();
 void InitializeDynamicAnnotations();
 
 void ReportRace(ThreadState *thr);

Modified: compiler-rt/trunk/lib/tsan/rtl/tsan_stat.cc
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/tsan/rtl/tsan_stat.cc?rev=191897&r1=191896&r2=191897&view=diff
==============================================================================
--- compiler-rt/trunk/lib/tsan/rtl/tsan_stat.cc (original)
+++ compiler-rt/trunk/lib/tsan/rtl/tsan_stat.cc Thu Oct  3 08:37:17 2013
@@ -371,6 +371,8 @@ void StatOutput(u64 *stat) {
   name[StatInt_sigprocmask]              = "  sigprocmask                     ";
   name[StatInt_backtrace]                = "  backtrace                       ";
   name[StatInt_backtrace_symbols]        = "  backtrace_symbols               ";
+  name[StatInt_dlopen]                   = "  dlopen                          ";
+  name[StatInt_dlclose]                  = "  dlclose                         ";
 
   name[StatAnnotation]                   = "Dynamic annotations               ";
   name[StatAnnotateHappensBefore]        = "  HappensBefore                   ";

Modified: compiler-rt/trunk/lib/tsan/rtl/tsan_stat.h
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/tsan/rtl/tsan_stat.h?rev=191897&r1=191896&r2=191897&view=diff
==============================================================================
--- compiler-rt/trunk/lib/tsan/rtl/tsan_stat.h (original)
+++ compiler-rt/trunk/lib/tsan/rtl/tsan_stat.h Thu Oct  3 08:37:17 2013
@@ -366,6 +366,8 @@ enum StatType {
   StatInt_sigprocmask,
   StatInt_backtrace,
   StatInt_backtrace_symbols,
+  StatInt_dlopen,
+  StatInt_dlclose,
 
   // Dynamic annotations.
   StatAnnotation,

Modified: compiler-rt/trunk/lib/tsan/rtl/tsan_suppressions.cc
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/tsan/rtl/tsan_suppressions.cc?rev=191897&r1=191896&r2=191897&view=diff
==============================================================================
--- compiler-rt/trunk/lib/tsan/rtl/tsan_suppressions.cc (original)
+++ compiler-rt/trunk/lib/tsan/rtl/tsan_suppressions.cc Thu Oct  3 08:37:17 2013
@@ -87,6 +87,11 @@ void InitializeSuppressions() {
 #endif
 }
 
+SuppressionContext *GetSuppressionContext() {
+  CHECK_NE(g_ctx, 0);
+  return g_ctx;
+}
+
 SuppressionType conv(ReportType typ) {
   if (typ == ReportTypeRace)
     return SuppressionRace;

Modified: compiler-rt/trunk/lib/tsan/rtl/tsan_suppressions.h
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/tsan/rtl/tsan_suppressions.h?rev=191897&r1=191896&r2=191897&view=diff
==============================================================================
--- compiler-rt/trunk/lib/tsan/rtl/tsan_suppressions.h (original)
+++ compiler-rt/trunk/lib/tsan/rtl/tsan_suppressions.h Thu Oct  3 08:37:17 2013
@@ -22,6 +22,7 @@ void InitializeSuppressions();
 void PrintMatchedSuppressions();
 uptr IsSuppressed(ReportType typ, const ReportStack *stack, Suppression **sp);
 uptr IsSuppressed(ReportType typ, const ReportLocation *loc, Suppression **sp);
+SuppressionContext *GetSuppressionContext();
 
 }  // namespace __tsan
 





More information about the llvm-commits mailing list