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) {
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);
return s;
}
@ -65,7 +66,7 @@ static void unref(ThreadState *thr, uptr pc, FdSync *s) {
CHECK_NE(s, &fdctx.globsync);
CHECK_NE(s, &fdctx.filesync);
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) {
uptr size = kTableSizeL2 * sizeof(FdDesc);
// 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);
MemoryResetRange(thr, (uptr)&fddesc, (uptr)p, size);
if (atomic_compare_exchange_strong(pl1, &l1, (uptr)p, memory_order_acq_rel))
l1 = (uptr)p;
else
user_free(thr, pc, p);
user_free(thr, pc, p, false);
}
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)))
return AllocatorReturnNull();
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;
if (ctx && ctx->initialized)
OnUserAlloc(thr, pc, (uptr)p, sz, true);
SignalUnsafeCall(thr, pc);
if (signal)
SignalUnsafeCall(thr, pc);
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)
OnUserFree(thr, pc, (uptr)p, true);
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) {

View File

@ -26,9 +26,9 @@ void AllocatorPrintStats();
// For user allocations.
void *user_alloc(ThreadState *thr, uptr pc, uptr sz,
uptr align = kDefaultAlignment);
uptr align = kDefaultAlignment, bool signal = true);
// 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_alloc_aligned(ThreadState *thr, uptr pc, uptr sz, uptr align);
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.
#ifdef NDEBUG
@ -37,7 +37,7 @@ int main() {
// Restore the original set.
assert(0 == sigprocmask(SIG_SETMASK, &old_set, NULL));
printf("DONE");
printf("DONE\n");
}
// CHECK: HANDLER