forked from OSchip/llvm-project
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:
parent
a08a8dc01d
commit
6373829449
|
@ -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
|
||||||
}
|
}
|
||||||
|
|
|
@ -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) {
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
Loading…
Reference in New Issue