[compiler-rt] r240576 - tsan: fix false positive between dlopen and dl_iterate_phdr

Dmitry Vyukov dvyukov at google.com
Wed Jun 24 12:49:32 PDT 2015


Author: dvyukov
Date: Wed Jun 24 14:49:32 2015
New Revision: 240576

URL: http://llvm.org/viewvc/llvm-project?rev=240576&view=rev
Log:
tsan: fix false positive between dlopen and dl_iterate_phdr

We see false reports between dlopen and dl_iterate_phdr.
This happens because tsan does not see dynamic linker
internal synchronization. Unpoison module names
in dl_iterate_phdr callback.


Added:
    compiler-rt/trunk/test/tsan/dl_iterate_phdr.cc
Modified:
    compiler-rt/trunk/lib/tsan/rtl/tsan_interceptors.cc

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=240576&r1=240575&r2=240576&view=diff
==============================================================================
--- compiler-rt/trunk/lib/tsan/rtl/tsan_interceptors.cc (original)
+++ compiler-rt/trunk/lib/tsan/rtl/tsan_interceptors.cc Wed Jun 24 14:49:32 2015
@@ -2144,6 +2144,46 @@ TSAN_INTERCEPTOR(int, vfork, int fake) {
   return WRAP(fork)(fake);
 }
 
+typedef int (*dl_iterate_phdr_cb_t)(__sanitizer_dl_phdr_info *info, SIZE_T size,
+                                    void *data);
+struct dl_iterate_phdr_data {
+  ThreadState *thr;
+  uptr pc;
+  dl_iterate_phdr_cb_t cb;
+  void *data;
+};
+
+static int dl_iterate_phdr_cb(__sanitizer_dl_phdr_info *info, SIZE_T size,
+                              void *data) {
+  dl_iterate_phdr_data *cbdata = (dl_iterate_phdr_data *)data;
+  // dlopen/dlclose allocate/free dynamic-linker-internal memory, which is later
+  // accessible in dl_iterate_phdr callback. But we don't see synchronization
+  // inside of dynamic linker, so we "unpoison" it here in order to not
+  // produce false reports. Ignoring malloc/free in dlopen/dlclose is not enough
+  // because some libc functions call __libc_dlopen.
+  bool reset = info && IsAppMem((uptr)info->dlpi_name) &&
+      *(u64*)MemToShadow((uptr)info->dlpi_name) != kShadowRodata;
+  if (reset)
+    MemoryResetRange(cbdata->thr, cbdata->pc, (uptr)info->dlpi_name,
+                     internal_strlen(info->dlpi_name));
+  int res = cbdata->cb(info, size, cbdata->data);
+  if (reset)
+    MemoryResetRange(cbdata->thr, cbdata->pc, (uptr)info->dlpi_name,
+                     internal_strlen(info->dlpi_name));
+  return res;
+}
+
+TSAN_INTERCEPTOR(int, dl_iterate_phdr, dl_iterate_phdr_cb_t cb, void *data) {
+  SCOPED_TSAN_INTERCEPTOR(dl_iterate_phdr, cb, data);
+  dl_iterate_phdr_data cbdata;
+  cbdata.thr = thr;
+  cbdata.pc = pc;
+  cbdata.cb = cb;
+  cbdata.data = data;
+  int res = REAL(dl_iterate_phdr)(dl_iterate_phdr_cb, &cbdata);
+  return res;
+}
+
 static int OnExit(ThreadState *thr) {
   int status = Finalize(thr);
   FlushStreams();
@@ -2577,6 +2617,7 @@ void InitializeInterceptors() {
 
   TSAN_INTERCEPT(fork);
   TSAN_INTERCEPT(vfork);
+  TSAN_INTERCEPT(dl_iterate_phdr);
   TSAN_INTERCEPT(on_exit);
   TSAN_INTERCEPT(__cxa_atexit);
   TSAN_INTERCEPT(_exit);

Added: compiler-rt/trunk/test/tsan/dl_iterate_phdr.cc
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/test/tsan/dl_iterate_phdr.cc?rev=240576&view=auto
==============================================================================
--- compiler-rt/trunk/test/tsan/dl_iterate_phdr.cc (added)
+++ compiler-rt/trunk/test/tsan/dl_iterate_phdr.cc Wed Jun 24 14:49:32 2015
@@ -0,0 +1,54 @@
+// RUN: %clangxx_tsan -O1 %s -DBUILD_SO -fPIC -shared -o %t-so.so
+// RUN: %clangxx_tsan -O1 %s -o %t && %run %t 2>&1 | FileCheck %s
+
+// If we mention TSAN_OPTIONS, the test won't run from test_output.sh script.
+
+#ifdef BUILD_SO
+
+#include "test.h"
+
+int exported_var = 0;
+
+#else  // BUILD_SO
+
+#include "test.h"
+#include <dlfcn.h>
+#include <link.h>
+#include <string.h>
+#include <string>
+
+static int callback(struct dl_phdr_info *info, size_t size, void *data) {
+  return !strcmp(info->dlpi_name, "non existent module");
+}
+
+void *thread(void *unused) {
+  for (int i = 0; i < 1000; i++) {
+    barrier_wait(&barrier);
+    dl_iterate_phdr(callback, 0);
+  }
+  return 0;
+}
+
+int main(int argc, char *argv[]) {
+  barrier_init(&barrier, 2);
+  std::string path = std::string(argv[0]) + std::string("-so.so");
+  pthread_t th;
+  pthread_create(&th, 0, thread, 0);
+  for (int i = 0; i < 1000; i++) {
+    barrier_wait(&barrier);
+    void *lib = dlopen(path.c_str(), RTLD_NOW);
+    if (!lib) {
+      printf("error in dlopen: %s\n", dlerror());
+      return 1;
+    }
+    dlclose(lib);
+  }
+  pthread_join(th, 0);
+  printf("DONE\n");
+  return 0;
+}
+
+#endif  // BUILD_SO
+
+// CHECK-NOT: WARNING: ThreadSanitizer: data race
+// CHECK: DONE





More information about the llvm-commits mailing list