tsan: fix false positive related to signals

Write interceptor calls malloc, which causes a false
unsafe-call-in-signal-handler report. See the test.

llvm-svn: 219784
This commit is contained in:
Dmitry Vyukov 2014-10-15 08:56:43 +00:00
parent a08a8dc01d
commit 6373829449
5 changed files with 42 additions and 12 deletions

View File

@ -48,7 +48,8 @@ static bool bogusfd(int fd) {
} }
static FdSync *allocsync(ThreadState *thr, uptr pc) { static FdSync *allocsync(ThreadState *thr, uptr pc) {
FdSync *s = (FdSync*)user_alloc(thr, pc, sizeof(FdSync)); FdSync *s = (FdSync*)user_alloc(thr, pc, sizeof(FdSync), kDefaultAlignment,
false);
atomic_store(&s->rc, 1, memory_order_relaxed); atomic_store(&s->rc, 1, memory_order_relaxed);
return s; return s;
} }
@ -65,7 +66,7 @@ static void unref(ThreadState *thr, uptr pc, FdSync *s) {
CHECK_NE(s, &fdctx.globsync); CHECK_NE(s, &fdctx.globsync);
CHECK_NE(s, &fdctx.filesync); CHECK_NE(s, &fdctx.filesync);
CHECK_NE(s, &fdctx.socksync); CHECK_NE(s, &fdctx.socksync);
user_free(thr, pc, s); user_free(thr, pc, s, false);
} }
} }
} }
@ -78,13 +79,13 @@ static FdDesc *fddesc(ThreadState *thr, uptr pc, int fd) {
if (l1 == 0) { if (l1 == 0) {
uptr size = kTableSizeL2 * sizeof(FdDesc); uptr size = kTableSizeL2 * sizeof(FdDesc);
// We need this to reside in user memory to properly catch races on it. // We need this to reside in user memory to properly catch races on it.
void *p = user_alloc(thr, pc, size); void *p = user_alloc(thr, pc, size, kDefaultAlignment, false);
internal_memset(p, 0, size); internal_memset(p, 0, size);
MemoryResetRange(thr, (uptr)&fddesc, (uptr)p, size); MemoryResetRange(thr, (uptr)&fddesc, (uptr)p, size);
if (atomic_compare_exchange_strong(pl1, &l1, (uptr)p, memory_order_acq_rel)) if (atomic_compare_exchange_strong(pl1, &l1, (uptr)p, memory_order_acq_rel))
l1 = (uptr)p; l1 = (uptr)p;
else else
user_free(thr, pc, p); user_free(thr, pc, p, false);
} }
return &((FdDesc*)l1)[fd % kTableSizeL2]; // NOLINT return &((FdDesc*)l1)[fd % kTableSizeL2]; // NOLINT
} }

View File

@ -76,7 +76,7 @@ static void SignalUnsafeCall(ThreadState *thr, uptr pc) {
} }
} }
void *user_alloc(ThreadState *thr, uptr pc, uptr sz, uptr align) { void *user_alloc(ThreadState *thr, uptr pc, uptr sz, uptr align, bool signal) {
if ((sz >= (1ull << 40)) || (align >= (1ull << 40))) if ((sz >= (1ull << 40)) || (align >= (1ull << 40)))
return AllocatorReturnNull(); return AllocatorReturnNull();
void *p = allocator()->Allocate(&thr->alloc_cache, sz, align); void *p = allocator()->Allocate(&thr->alloc_cache, sz, align);
@ -84,15 +84,17 @@ void *user_alloc(ThreadState *thr, uptr pc, uptr sz, uptr align) {
return 0; return 0;
if (ctx && ctx->initialized) if (ctx && ctx->initialized)
OnUserAlloc(thr, pc, (uptr)p, sz, true); OnUserAlloc(thr, pc, (uptr)p, sz, true);
SignalUnsafeCall(thr, pc); if (signal)
SignalUnsafeCall(thr, pc);
return p; return p;
} }
void user_free(ThreadState *thr, uptr pc, void *p) { void user_free(ThreadState *thr, uptr pc, void *p, bool signal) {
if (ctx && ctx->initialized) if (ctx && ctx->initialized)
OnUserFree(thr, pc, (uptr)p, true); OnUserFree(thr, pc, (uptr)p, true);
allocator()->Deallocate(&thr->alloc_cache, p); allocator()->Deallocate(&thr->alloc_cache, p);
SignalUnsafeCall(thr, pc); if (signal)
SignalUnsafeCall(thr, pc);
} }
void OnUserAlloc(ThreadState *thr, uptr pc, uptr p, uptr sz, bool write) { void OnUserAlloc(ThreadState *thr, uptr pc, uptr p, uptr sz, bool write) {

View File

@ -26,9 +26,9 @@ void AllocatorPrintStats();
// For user allocations. // For user allocations.
void *user_alloc(ThreadState *thr, uptr pc, uptr sz, void *user_alloc(ThreadState *thr, uptr pc, uptr sz,
uptr align = kDefaultAlignment); uptr align = kDefaultAlignment, bool signal = true);
// Does not accept NULL. // Does not accept NULL.
void user_free(ThreadState *thr, uptr pc, void *p); void user_free(ThreadState *thr, uptr pc, void *p, bool signal = true);
void *user_realloc(ThreadState *thr, uptr pc, void *p, uptr sz); void *user_realloc(ThreadState *thr, uptr pc, void *p, uptr sz);
void *user_alloc_aligned(ThreadState *thr, uptr pc, uptr sz, uptr align); void *user_alloc_aligned(ThreadState *thr, uptr pc, uptr sz, uptr align);
uptr user_alloc_usable_size(const void *p); uptr user_alloc_usable_size(const void *p);

View File

@ -0,0 +1,27 @@
// RUN: %clang_tsan -O1 %s -o %t && %run %t 2>&1 | FileCheck %s
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <string.h>
#include <sys/types.h>
#include <unistd.h>
static void handler(int, siginfo_t*, void*) {
const char *str = "HELLO FROM SIGNAL\n";
write(2, str, strlen(str));
}
int main() {
struct sigaction act = {};
act.sa_sigaction = &handler;
sigaction(SIGPROF, &act, 0);
kill(getpid(), SIGPROF);
sleep(1);
fprintf(stderr, "DONE\n");
return 0;
}
// CHECK-NOT: WARNING: ThreadSanitizer
// CHECK: HELLO FROM SIGNAL
// CHECK: DONE

View File

@ -1,4 +1,4 @@
// RUN: %clangxx_tsan -O1 %s -o %t && %deflake %run %t | FileCheck %s // RUN: %clangxx_tsan -O1 %s -o %t && %run %t 2>&1 | FileCheck %s
// Always enable asserts. // Always enable asserts.
#ifdef NDEBUG #ifdef NDEBUG
@ -37,7 +37,7 @@ int main() {
// Restore the original set. // Restore the original set.
assert(0 == sigprocmask(SIG_SETMASK, &old_set, NULL)); assert(0 == sigprocmask(SIG_SETMASK, &old_set, NULL));
printf("DONE"); printf("DONE\n");
} }
// CHECK: HANDLER // CHECK: HANDLER