[compiler-rt] 09910aa - [tsan] fcntl interceptor with F_DUPFD and F_DUPFD_CLOEXEC support (#221064)
via llvm-commits
llvm-commits at lists.llvm.org
Sun Oct 4 23:14:30 PDT 2026
Author: Mike Aizatsky
Date: 2026-10-05T06:14:23Z
New Revision: 09910aa044808dfbfe1e0f96b5e39260789212fb
URL: https://github.com/llvm/llvm-project/commit/09910aa044808dfbfe1e0f96b5e39260789212fb
DIFF: https://github.com/llvm/llvm-project/commit/09910aa044808dfbfe1e0f96b5e39260789212fb.diff
LOG: [tsan] fcntl interceptor with F_DUPFD and F_DUPFD_CLOEXEC support (#221064)
behaves like dup
fixes https://github.com/rust-lang/rust/issues/130037 and bunch of
others
Added:
compiler-rt/test/tsan/Linux/fd_fcntl_dupfd_cloexec_norace.cpp
Modified:
compiler-rt/lib/tsan/rtl/tsan_interceptors_posix.cpp
Removed:
################################################################################
diff --git a/compiler-rt/lib/tsan/rtl/tsan_interceptors_posix.cpp b/compiler-rt/lib/tsan/rtl/tsan_interceptors_posix.cpp
index b2ba666741e89..ed16e15a25edd 100644
--- a/compiler-rt/lib/tsan/rtl/tsan_interceptors_posix.cpp
+++ b/compiler-rt/lib/tsan/rtl/tsan_interceptors_posix.cpp
@@ -1827,29 +1827,64 @@ TSAN_INTERCEPTOR(int, creat64, const char *name, int mode) {
#define TSAN_MAYBE_INTERCEPT_CREAT64
#endif
-TSAN_INTERCEPTOR(int, dup, int oldfd) {
- SCOPED_TSAN_INTERCEPTOR(dup, oldfd);
- int newfd = REAL(dup)(oldfd);
+static int HandleDupResult(ThreadState* thr, uptr pc, int oldfd, int newfd,
+ bool write) {
if (oldfd >= 0 && newfd >= 0 && newfd != oldfd)
- FdDup(thr, pc, oldfd, newfd, true);
+ FdDup(thr, pc, oldfd, newfd, write);
return newfd;
}
+#if SANITIZER_LINUX
+// These values are part of the Linux UAPI and are the same on all Linux
+// architectures.
+static const int kF_DUPFD = 0;
+static const int kF_DUPFD_CLOEXEC = 1030;
+
+// fcntl accepts either an int or a pointer as its optional argument. Reading
+// it as uptr follows libc's implementation strategy and preserves either value
+// on the ABIs supported by TSan.
+# define TSAN_FCNTL_INTERCEPTOR(func) \
+ TSAN_INTERCEPTOR(int, func, int oldfd, int cmd, ...) { \
+ va_list ap; \
+ va_start(ap, cmd); \
+ uptr arg = va_arg(ap, uptr); \
+ va_end(ap); \
+ SCOPED_TSAN_INTERCEPTOR(func, oldfd, cmd, arg); \
+ int newfd = REAL(func)(oldfd, cmd, arg); \
+ if (cmd == kF_DUPFD || cmd == kF_DUPFD_CLOEXEC) \
+ return HandleDupResult(thr, pc, oldfd, newfd, true); \
+ return newfd; \
+ }
+
+TSAN_FCNTL_INTERCEPTOR(fcntl)
+# if SANITIZER_INTERCEPT_FCNTL64
+TSAN_FCNTL_INTERCEPTOR(fcntl64)
+# define TSAN_MAYBE_INTERCEPT_FCNTL64 TSAN_INTERCEPT(fcntl64)
+# else
+# define TSAN_MAYBE_INTERCEPT_FCNTL64
+# endif
+# undef TSAN_FCNTL_INTERCEPTOR
+# define TSAN_MAYBE_INTERCEPT_FCNTL TSAN_INTERCEPT(fcntl)
+#else
+# define TSAN_MAYBE_INTERCEPT_FCNTL
+# define TSAN_MAYBE_INTERCEPT_FCNTL64
+#endif
+
+TSAN_INTERCEPTOR(int, dup, int oldfd) {
+ SCOPED_TSAN_INTERCEPTOR(dup, oldfd);
+ return HandleDupResult(thr, pc, oldfd, REAL(dup)(oldfd), true);
+}
+
TSAN_INTERCEPTOR(int, dup2, int oldfd, int newfd) {
SCOPED_TSAN_INTERCEPTOR(dup2, oldfd, newfd);
- int newfd2 = REAL(dup2)(oldfd, newfd);
- if (oldfd >= 0 && newfd2 >= 0 && newfd2 != oldfd)
- FdDup(thr, pc, oldfd, newfd2, false);
- return newfd2;
+ return HandleDupResult(thr, pc, oldfd, REAL(dup2)(oldfd, newfd), false);
}
#if !SANITIZER_APPLE
TSAN_INTERCEPTOR(int, dup3, int oldfd, int newfd, int flags) {
SCOPED_TSAN_INTERCEPTOR(dup3, oldfd, newfd, flags);
- int newfd2 = REAL(dup3)(oldfd, newfd, flags);
- if (oldfd >= 0 && newfd2 >= 0 && newfd2 != oldfd)
- FdDup(thr, pc, oldfd, newfd2, false);
- return newfd2;
+ return HandleDupResult(thr, pc, oldfd, REAL(dup3)(oldfd, newfd, flags),
+ false);
}
#endif
@@ -3142,6 +3177,8 @@ void InitializeInterceptors() {
TSAN_MAYBE_INTERCEPT_OPEN64;
TSAN_INTERCEPT(creat);
TSAN_MAYBE_INTERCEPT_CREAT64;
+ TSAN_MAYBE_INTERCEPT_FCNTL;
+ TSAN_MAYBE_INTERCEPT_FCNTL64;
TSAN_INTERCEPT(dup);
TSAN_INTERCEPT(dup2);
TSAN_INTERCEPT(dup3);
diff --git a/compiler-rt/test/tsan/Linux/fd_fcntl_dupfd_cloexec_norace.cpp b/compiler-rt/test/tsan/Linux/fd_fcntl_dupfd_cloexec_norace.cpp
new file mode 100644
index 0000000000000..2bd9928934e01
--- /dev/null
+++ b/compiler-rt/test/tsan/Linux/fd_fcntl_dupfd_cloexec_norace.cpp
@@ -0,0 +1,46 @@
+// RUN: %clangxx_tsan -O1 %s -o %t && %run %t 2>&1 | FileCheck %s
+
+#include <fcntl.h>
+#include <pthread.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+int value;
+int duplicate_write_fd;
+
+void *writer(void *) {
+ value = 1;
+ if (write(duplicate_write_fd, ".", 1) != 1)
+ abort();
+ return nullptr;
+}
+
+int main() {
+ int pipe_fds[2];
+ if (pipe2(pipe_fds, O_CLOEXEC) != 0)
+ abort();
+
+ duplicate_write_fd = fcntl(pipe_fds[1], F_DUPFD_CLOEXEC, 0);
+ if (duplicate_write_fd < 0)
+ abort();
+
+ pthread_t thread;
+ pthread_create(&thread, nullptr, writer, nullptr);
+
+ char byte;
+ if (read(pipe_fds[0], &byte, 1) != 1)
+ abort();
+ if (value != 1)
+ abort();
+
+ pthread_join(thread, nullptr);
+ close(duplicate_write_fd);
+ close(pipe_fds[0]);
+ close(pipe_fds[1]);
+ fprintf(stderr, "DONE\n");
+ return 0;
+}
+
+// CHECK-NOT: WARNING: ThreadSanitizer: data race
+// CHECK: DONE
More information about the llvm-commits
mailing list