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:
Dmitry Vyukov 2021-11-11 16:17:58 +01:00
parent 8fd2f56c99
commit 82de586d4b
2 changed files with 65 additions and 0 deletions

View File

@ -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

View File

@ -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