tsan: ignore all interceptors coming directly from JVM

llvm-svn: 191152
diff --git a/compiler-rt/lib/tsan/lit_tests/java.h b/compiler-rt/lib/tsan/lit_tests/java.h
index 0409419..7aa0bca 100644
--- a/compiler-rt/lib/tsan/lit_tests/java.h
+++ b/compiler-rt/lib/tsan/lit_tests/java.h
@@ -5,6 +5,7 @@
 
 extern "C" {
 typedef unsigned long jptr;  // NOLINT
+void __tsan_java_preinit(const char *libjvm_path);
 void __tsan_java_init(jptr heap_begin, jptr heap_size);
 int  __tsan_java_fini();
 void __tsan_java_alloc(jptr ptr, jptr size);
diff --git a/compiler-rt/lib/tsan/lit_tests/java_alloc.cc b/compiler-rt/lib/tsan/lit_tests/java_alloc.cc
index 4dbce70..079c9b9 100644
--- a/compiler-rt/lib/tsan/lit_tests/java_alloc.cc
+++ b/compiler-rt/lib/tsan/lit_tests/java_alloc.cc
@@ -20,6 +20,7 @@
 
 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));
diff --git a/compiler-rt/lib/tsan/lit_tests/java_lock.cc b/compiler-rt/lib/tsan/lit_tests/java_lock.cc
index d9db103..c019597 100644
--- a/compiler-rt/lib/tsan/lit_tests/java_lock.cc
+++ b/compiler-rt/lib/tsan/lit_tests/java_lock.cc
@@ -16,6 +16,7 @@
 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);
diff --git a/compiler-rt/lib/tsan/rtl/tsan_interceptors.cc b/compiler-rt/lib/tsan/rtl/tsan_interceptors.cc
index 0338f5a..e5bc533 100644
--- a/compiler-rt/lib/tsan/rtl/tsan_interceptors.cc
+++ b/compiler-rt/lib/tsan/rtl/tsan_interceptors.cc
@@ -128,6 +128,21 @@
   int pending_signal_count;
   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;
+}
+
 }  // namespace __tsan
 
 static SignalContext *SigCtx(ThreadState *thr) {
@@ -191,7 +206,7 @@
       Printf("FATAL: ThreadSanitizer: failed to intercept %s\n", #func); \
       Die(); \
     } \
-    if (thr->in_rtl > 1) \
+    if (thr->in_rtl > 1 || libjvm_check(pc)) \
       return REAL(func)(__VA_ARGS__); \
 /**/
 
diff --git a/compiler-rt/lib/tsan/rtl/tsan_interface_java.cc b/compiler-rt/lib/tsan/rtl/tsan_interface_java.cc
index 358fd15..2ac3249 100644
--- a/compiler-rt/lib/tsan/rtl/tsan_interface_java.cc
+++ b/compiler-rt/lib/tsan/rtl/tsan_interface_java.cc
@@ -18,6 +18,7 @@
 #include "sanitizer_common/sanitizer_common.h"
 #include "sanitizer_common/sanitizer_placement_new.h"
 #include "sanitizer_common/sanitizer_stacktrace.h"
+#include "sanitizer_common/sanitizer_procmaps.h"
 
 using namespace __tsan;  // NOLINT
 
@@ -95,6 +96,8 @@
 
 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;
@@ -163,6 +166,17 @@
   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);
diff --git a/compiler-rt/lib/tsan/rtl/tsan_interface_java.h b/compiler-rt/lib/tsan/rtl/tsan_interface_java.h
index 9ac78e0..a4a05aa 100644
--- a/compiler-rt/lib/tsan/rtl/tsan_interface_java.h
+++ b/compiler-rt/lib/tsan/rtl/tsan_interface_java.h
@@ -34,7 +34,11 @@
 
 typedef unsigned long jptr;  // NOLINT
 
-// Must be called before any other callback from Java.
+// 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.
 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).