[compiler-rt] r202400 - tsan: intercept vfork
Dmitry Vyukov
dvyukov at google.com
Thu Feb 27 06:36:16 PST 2014
Author: dvyukov
Date: Thu Feb 27 08:36:16 2014
New Revision: 202400
URL: http://llvm.org/viewvc/llvm-project?rev=202400&view=rev
Log:
tsan: intercept vfork
this fixes obscure false positives
see the comments and the test for details
Added:
compiler-rt/trunk/test/tsan/vfork.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=202400&r1=202399&r2=202400&view=diff
==============================================================================
--- compiler-rt/trunk/lib/tsan/rtl/tsan_interceptors.cc (original)
+++ compiler-rt/trunk/lib/tsan/rtl/tsan_interceptors.cc Thu Feb 27 08:36:16 2014
@@ -1903,6 +1903,23 @@ TSAN_INTERCEPTOR(int, fork, int fake) {
return pid;
}
+TSAN_INTERCEPTOR(int, vfork, int fake) {
+ // Some programs (e.g. openjdk) call close for all file descriptors
+ // in the child process. Under tsan it leads to false positives, because
+ // address space is shared, so the parent process also thinks that
+ // the descriptors are closed (while they are actually not).
+ // This leads to false positives due to missed synchronization.
+ // Strictly saying this is undefined behavior, because vfork child is not
+ // allowed to call any functions other than exec/exit. But this is what
+ // openjdk does, so we want to handle it.
+ // We could disable interceptors in the child process. But it's not possible
+ // to simply intercept and wrap vfork, because vfork child is not allowed
+ // to return from the function that calls vfork, and that's exactly what
+ // we would do. So this would require some assembly trickery as well.
+ // Instead we simply turn vfork into fork.
+ return WRAP(fork)(fake);
+}
+
static int OnExit(ThreadState *thr) {
int status = Finalize(thr);
REAL(fflush)(0);
@@ -2289,6 +2306,7 @@ void InitializeInterceptors() {
TSAN_INTERCEPT(munlockall);
TSAN_INTERCEPT(fork);
+ TSAN_INTERCEPT(vfork);
TSAN_INTERCEPT(dlopen);
TSAN_INTERCEPT(dlclose);
TSAN_INTERCEPT(on_exit);
Added: compiler-rt/trunk/test/tsan/vfork.cc
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/test/tsan/vfork.cc?rev=202400&view=auto
==============================================================================
--- compiler-rt/trunk/test/tsan/vfork.cc (added)
+++ compiler-rt/trunk/test/tsan/vfork.cc Thu Feb 27 08:36:16 2014
@@ -0,0 +1,51 @@
+// RUN: %clangxx_tsan -O1 %s -o %t && %t 2>&1 | FileCheck %s
+#include <pthread.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/types.h>
+
+int fds[2];
+int X;
+
+void *Thread1(void *x) {
+ X = 42;
+ write(fds[1], "a", 1);
+ return NULL;
+}
+
+void *Thread2(void *x) {
+ char buf;
+ while (read(fds[0], &buf, 1) != 1) {
+ }
+ X = 43;
+ return NULL;
+}
+
+int main() {
+ pipe(fds);
+ int pid = vfork();
+ if (pid < 0) {
+ printf("FAIL to vfork\n");
+ exit(1);
+ }
+ if (pid == 0) { // child
+ // Closing of fds must not affect parent process.
+ // Strictly saying this is undefined behavior, because vfork child is not
+ // allowed to call any functions other than exec/exit. But this is what
+ // openjdk does.
+ close(fds[0]);
+ close(fds[1]);
+ _exit(0);
+ }
+ pthread_t t[2];
+ pthread_create(&t[0], NULL, Thread1, NULL);
+ pthread_create(&t[1], NULL, Thread2, NULL);
+ pthread_join(t[0], NULL);
+ pthread_join(t[1], NULL);
+ printf("DONE\n");
+}
+
+// CHECK-NOT: WARNING: ThreadSanitizer: data race
+// CHECK-NOT: FAIL to vfork
+// CHECK: DONE
More information about the llvm-commits
mailing list