[compiler-rt] r317735 - Correct atexit(3) support in TSan/NetBSD
Kamil Rytarowski via llvm-commits
llvm-commits at lists.llvm.org
Wed Nov 8 14:34:17 PST 2017
Author: kamil
Date: Wed Nov 8 14:34:17 2017
New Revision: 317735
URL: http://llvm.org/viewvc/llvm-project?rev=317735&view=rev
Log:
Correct atexit(3) support in TSan/NetBSD
Summary:
The NetBSD specific implementation of cxa_atexit() does not
preserve the 2nd argument if dso is equal to NULL.
Changes:
- Split paths of handling intercepted __cxa_atexit() and atexit(3).
This affects all supported Operating Systems.
- Add a local stack-like structure to hold the __cxa_atexit() context.
atexit(3) is documented in the C standard as calling callback from the
earliest to the oldest entry. This path also fixes potential ABI
problem of passing an argument to a function from the atexit(3)
callback mechanism.
- Add new test to ensure LIFO style of atexit(3) callbacks: atexit3.cc
Proposal to change the behavior of __cxa_atexit() in NetBSD has been rejected.
With the above changes TSan/NetBSD with the current tsan_interceptors.cc
can bootstrap into operation.
Sponsored by <The NetBSD Foundation>
Reviewers: vitalybuka, dvyukov, joerg, kcc, eugenis
Reviewed By: dvyukov
Subscribers: kubamracek, llvm-commits, #sanitizers
Tags: #sanitizers
Differential Revision: https://reviews.llvm.org/D39619
Added:
compiler-rt/trunk/test/tsan/atexit3.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=317735&r1=317734&r2=317735&view=diff
==============================================================================
--- compiler-rt/trunk/lib/tsan/rtl/tsan_interceptors.cc (original)
+++ compiler-rt/trunk/lib/tsan/rtl/tsan_interceptors.cc Wed Nov 8 14:34:17 2017
@@ -231,6 +231,13 @@ struct ThreadSignalContext {
__sanitizer_sigset_t oldset;
};
+// The sole reason tsan wraps atexit callbacks is to establish synchronization
+// between callback setup and callback execution.
+struct AtExitCtx {
+ void (*f)();
+ void *arg;
+};
+
// InterceptorContext holds all global data required for interceptors.
// It's explicitly constructed in InitializeInterceptors with placement new
// and is never destroyed. This allows usage of members with non-trivial
@@ -244,8 +251,11 @@ struct InterceptorContext {
unsigned finalize_key;
#endif
+ BlockingMutex atexit_mu;
+ Vector<struct AtExitCtx *> AtExitStack;
+
InterceptorContext()
- : libignore(LINKER_INITIALIZED) {
+ : libignore(LINKER_INITIALIZED), AtExitStack(MBlockAtExit) {
}
};
@@ -398,17 +408,25 @@ TSAN_INTERCEPTOR(int, pause, int fake) {
return BLOCK_REAL(pause)(fake);
}
-// The sole reason tsan wraps atexit callbacks is to establish synchronization
-// between callback setup and callback execution.
-struct AtExitCtx {
- void (*f)();
- void *arg;
-};
+static void at_exit_wrapper() {
+ AtExitCtx *ctx;
+ {
+ // Ensure thread-safety.
+ BlockingMutexLock l(&interceptor_ctx()->atexit_mu);
+
+ // Pop AtExitCtx from the top of the stack of callback functions
+ uptr element = interceptor_ctx()->AtExitStack.Size() - 1;
+ ctx = interceptor_ctx()->AtExitStack[element];
+ interceptor_ctx()->AtExitStack.PopBack();
+ }
-static void at_exit_wrapper(void *arg) {
- ThreadState *thr = cur_thread();
- uptr pc = 0;
- Acquire(thr, pc, (uptr)arg);
+ Acquire(cur_thread(), (uptr)0, (uptr)ctx);
+ ((void(*)())ctx->f)();
+ InternalFree(ctx);
+}
+
+static void cxa_at_exit_wrapper(void *arg) {
+ Acquire(cur_thread(), 0, (uptr)arg);
AtExitCtx *ctx = (AtExitCtx*)arg;
((void(*)(void *arg))ctx->f)(ctx->arg);
InternalFree(ctx);
@@ -444,7 +462,22 @@ static int setup_at_exit_wrapper(ThreadS
// Memory allocation in __cxa_atexit will race with free during exit,
// because we do not see synchronization around atexit callback list.
ThreadIgnoreBegin(thr, pc);
- int res = REAL(__cxa_atexit)(at_exit_wrapper, ctx, dso);
+ int res;
+ if (!dso) {
+ // NetBSD does not preserve the 2nd argument if dso is equal to 0
+ // Store ctx in a local stack-like structure
+
+ // Ensure thread-safety.
+ BlockingMutexLock l(&interceptor_ctx()->atexit_mu);
+
+ res = REAL(__cxa_atexit)((void (*)(void *a))at_exit_wrapper, 0, 0);
+ // Push AtExitCtx on the top of the stack of callback functions
+ if (!res) {
+ interceptor_ctx()->AtExitStack.PushBack(ctx);
+ }
+ } else {
+ res = REAL(__cxa_atexit)(cxa_at_exit_wrapper, ctx, dso);
+ }
ThreadIgnoreEnd(thr, pc);
return res;
}
Added: compiler-rt/trunk/test/tsan/atexit3.cc
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/test/tsan/atexit3.cc?rev=317735&view=auto
==============================================================================
--- compiler-rt/trunk/test/tsan/atexit3.cc (added)
+++ compiler-rt/trunk/test/tsan/atexit3.cc Wed Nov 8 14:34:17 2017
@@ -0,0 +1,41 @@
+// RUN: %clang_tsan -O1 %s -o %t && %run %t 2>&1 | FileCheck %s
+
+#include <stdio.h>
+#include <stdlib.h>
+
+static void atexit5() {
+ fprintf(stderr, "5");
+}
+
+static void atexit4() {
+ fprintf(stderr, "4");
+}
+
+static void atexit3() {
+ fprintf(stderr, "3");
+}
+
+static void atexit2() {
+ fprintf(stderr, "2");
+}
+
+static void atexit1() {
+ fprintf(stderr, "1");
+}
+
+static void atexit0() {
+ fprintf(stderr, "\n");
+}
+
+int main() {
+ atexit(atexit0);
+ atexit(atexit1);
+ atexit(atexit2);
+ atexit(atexit3);
+ atexit(atexit4);
+ atexit(atexit5);
+}
+
+// CHECK-NOT: FATAL: ThreadSanitizer
+// CHECK-NOT: WARNING: ThreadSanitizer
+// CHECK: 54321
More information about the llvm-commits
mailing list