summaryrefslogtreecommitdiffstats
path: root/compiler-rt/lib/tsan/rtl
diff options
context:
space:
mode:
authorDmitry Vyukov <dvyukov@google.com>2016-02-23 17:16:26 +0000
committerDmitry Vyukov <dvyukov@google.com>2016-02-23 17:16:26 +0000
commitb2be09802638802deebace5237f1d804977517d0 (patch)
treeeac314a5640394619d7d07c90d490c7051db0342 /compiler-rt/lib/tsan/rtl
parentcc43f581b4d23af28cab702e51e50a576ad7f4c1 (diff)
downloadbcm5719-llvm-b2be09802638802deebace5237f1d804977517d0.tar.gz
bcm5719-llvm-b2be09802638802deebace5237f1d804977517d0.zip
tsan: fix signal handling in ignored libraries
The first issue is that we longjmp from ScopedInterceptor scope when called from an ignored lib. This leaves thr->in_ignored_lib set. This, in turn, disables handling of sigaction. This, in turn, corrupts tsan state since signals delivered asynchronously. Another issue is that we can ignore synchronization in asignal handler, if the signal is delivered into an IgnoreSync region. Since signals are generally asynchronous, they should ignore memory access/synchronization/interceptor ignores. This could lead to false positives in signal handlers. llvm-svn: 261658
Diffstat (limited to 'compiler-rt/lib/tsan/rtl')
-rw-r--r--compiler-rt/lib/tsan/rtl/tsan_interceptors.cc32
1 files changed, 26 insertions, 6 deletions
diff --git a/compiler-rt/lib/tsan/rtl/tsan_interceptors.cc b/compiler-rt/lib/tsan/rtl/tsan_interceptors.cc
index f9d5b0f8786..e3f2c53226a 100644
--- a/compiler-rt/lib/tsan/rtl/tsan_interceptors.cc
+++ b/compiler-rt/lib/tsan/rtl/tsan_interceptors.cc
@@ -581,8 +581,11 @@ DEFINE_REAL(int, __sigsetjmp, void *env)
#endif // SANITIZER_MAC
TSAN_INTERCEPTOR(void, longjmp, uptr *env, int val) {
+ // Note: if we call REAL(longjmp) in the context of ScopedInterceptor,
+ // bad things will happen. We will jump over ScopedInterceptor dtor and can
+ // leave thr->in_ignored_lib set.
{
- SCOPED_TSAN_INTERCEPTOR(longjmp, env, val);
+ SCOPED_INTERCEPTOR_RAW(longjmp, env, val);
}
LongJmp(cur_thread(), env);
REAL(longjmp)(env, val);
@@ -590,7 +593,7 @@ TSAN_INTERCEPTOR(void, longjmp, uptr *env, int val) {
TSAN_INTERCEPTOR(void, siglongjmp, uptr *env, int val) {
{
- SCOPED_TSAN_INTERCEPTOR(siglongjmp, env, val);
+ SCOPED_INTERCEPTOR_RAW(siglongjmp, env, val);
}
LongJmp(cur_thread(), env);
REAL(siglongjmp)(env, val);
@@ -1947,6 +1950,18 @@ static void CallUserSignalHandler(ThreadState *thr, bool sync, bool acquire,
bool sigact, int sig, my_siginfo_t *info, void *uctx) {
if (acquire)
Acquire(thr, 0, (uptr)&sigactions[sig]);
+ // Signals are generally asynchronous, so if we receive a signals when
+ // ignores are enabled we should disable ignores. This is critical for sync
+ // and interceptors, because otherwise we can miss syncronization and report
+ // false races.
+ int ignore_reads_and_writes = thr->ignore_reads_and_writes;
+ int ignore_interceptors = thr->ignore_interceptors;
+ int ignore_sync = thr->ignore_sync;
+ if (!ctx->after_multithreaded_fork) {
+ thr->ignore_reads_and_writes = 0;
+ thr->ignore_interceptors = 0;
+ thr->ignore_sync = 0;
+ }
// Ensure that the handler does not spoil errno.
const int saved_errno = errno;
errno = 99;
@@ -1962,6 +1977,11 @@ static void CallUserSignalHandler(ThreadState *thr, bool sync, bool acquire,
else
((sighandler_t)pc)(sig);
}
+ if (!ctx->after_multithreaded_fork) {
+ thr->ignore_reads_and_writes = ignore_reads_and_writes;
+ thr->ignore_interceptors = ignore_interceptors;
+ thr->ignore_sync = ignore_sync;
+ }
// We do not detect errno spoiling for SIGTERM,
// because some SIGTERM handlers do spoil errno but reraise SIGTERM,
// tsan reports false positive in such case.
@@ -2033,11 +2053,8 @@ void ALWAYS_INLINE rtl_generic_sighandler(bool sigact, int sig,
if (sctx && atomic_load(&sctx->in_blocking_func, memory_order_relaxed)) {
// We ignore interceptors in blocking functions,
// temporary enbled them again while we are calling user function.
- int const i = thr->ignore_interceptors;
- thr->ignore_interceptors = 0;
atomic_store(&sctx->in_blocking_func, 0, memory_order_relaxed);
CallUserSignalHandler(thr, sync, true, sigact, sig, info, ctx);
- thr->ignore_interceptors = i;
atomic_store(&sctx->in_blocking_func, 1, memory_order_relaxed);
} else {
// Be very conservative with when we do acquire in this case.
@@ -2075,7 +2092,10 @@ static void rtl_sigaction(int sig, my_siginfo_t *info, void *ctx) {
}
TSAN_INTERCEPTOR(int, sigaction, int sig, sigaction_t *act, sigaction_t *old) {
- SCOPED_TSAN_INTERCEPTOR(sigaction, sig, act, old);
+ // Note: if we call REAL(sigaction) directly for any reason without proxying
+ // the signal handler through rtl_sigaction, very bad things will happen.
+ // The handler will run synchronously and corrupt tsan per-thread state.
+ SCOPED_INTERCEPTOR_RAW(sigaction, sig, act, old);
if (old)
internal_memcpy(old, &sigactions[sig], sizeof(*old));
if (act == 0)
OpenPOWER on IntegriCloud