forked from OSchip/llvm-project
tsan: intercept clone
gtest uses clone for death tests and it needs the same handling as fork to prevent deadlock (take runtime mutexes before and release them after). Reviewed By: melver Differential Revision: https://reviews.llvm.org/D113677
This commit is contained in:
parent
8fd2f56c99
commit
82de586d4b
|
@ -2210,6 +2210,30 @@ TSAN_INTERCEPTOR(int, vfork, int fake) {
|
|||
return WRAP(fork)(fake);
|
||||
}
|
||||
|
||||
TSAN_INTERCEPTOR(int, clone, int (*fn)(void *), void *stack, int flags,
|
||||
void *arg, int *parent_tid, void *tls, pid_t *child_tid) {
|
||||
SCOPED_INTERCEPTOR_RAW(clone, fn, stack, flags, arg, parent_tid, tls,
|
||||
child_tid);
|
||||
struct Arg {
|
||||
int (*fn)(void *);
|
||||
void *arg;
|
||||
};
|
||||
auto wrapper = +[](void *p) -> int {
|
||||
auto *thr = cur_thread();
|
||||
uptr pc = GET_CURRENT_PC();
|
||||
ForkChildAfter(thr, pc);
|
||||
FdOnFork(thr, pc);
|
||||
auto *arg = static_cast<Arg *>(p);
|
||||
return arg->fn(arg->arg);
|
||||
};
|
||||
ForkBefore(thr, pc);
|
||||
Arg arg_wrapper = {fn, arg};
|
||||
int pid = REAL(clone)(wrapper, stack, flags, &arg_wrapper, parent_tid, tls,
|
||||
child_tid);
|
||||
ForkParentAfter(thr, pc);
|
||||
return pid;
|
||||
}
|
||||
|
||||
#if !SANITIZER_MAC && !SANITIZER_ANDROID
|
||||
typedef int (*dl_iterate_phdr_cb_t)(__sanitizer_dl_phdr_info *info, SIZE_T size,
|
||||
void *data);
|
||||
|
@ -2841,6 +2865,7 @@ void InitializeInterceptors() {
|
|||
|
||||
TSAN_INTERCEPT(fork);
|
||||
TSAN_INTERCEPT(vfork);
|
||||
TSAN_INTERCEPT(clone);
|
||||
#if !SANITIZER_ANDROID
|
||||
TSAN_INTERCEPT(dl_iterate_phdr);
|
||||
#endif
|
||||
|
|
|
@ -0,0 +1,40 @@
|
|||
// RUN: %clangxx_tsan -O1 %s -o %t && %env_tsan_opts=atexit_sleep_ms=0 %run %t 2>&1 | FileCheck %s
|
||||
#include "test.h"
|
||||
#include <errno.h>
|
||||
#include <sched.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/wait.h>
|
||||
|
||||
long counter;
|
||||
|
||||
static void *incrementer(void *arg) {
|
||||
for (;;)
|
||||
__sync_fetch_and_add(&counter, 1);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int cloned(void *arg) {
|
||||
for (int i = 0; i < 1000; i++)
|
||||
__sync_fetch_and_add(&counter, 1);
|
||||
exit(0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int main() {
|
||||
barrier_init(&barrier, 2);
|
||||
pthread_t th;
|
||||
pthread_create(&th, 0, incrementer, 0);
|
||||
for (int i = 0; i < 100; i++) {
|
||||
char stack[64 << 10] __attribute__((aligned(64)));
|
||||
int pid = clone(cloned, stack + sizeof(stack), SIGCHLD, 0);
|
||||
if (pid == -1) {
|
||||
fprintf(stderr, "failed to clone: %d\n", errno);
|
||||
exit(1);
|
||||
}
|
||||
while (wait(0) != pid) {
|
||||
}
|
||||
}
|
||||
fprintf(stderr, "DONE\n");
|
||||
}
|
||||
|
||||
// CHECK: DONE
|
Loading…
Reference in New Issue