[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