
We used to deduplicate based on the race address to prevent lots of repeated reports about the same race. But now we clear the shadow for the racy address in DoReportRace: // This prevents trapping on this address in future. for (uptr i = 0; i < kShadowCnt; i++) StoreShadow(&shadow_mem[i], i == 0 ? Shadow::kRodata : Shadow::kEmpty); It should have the same effect of not reporting duplicates (and actually better because it's automatically reset when the memory is reallocated). So drop the address deduplication code. Both simpler and faster. Reviewed By: melver Differential Revision: https://reviews.llvm.org/D130240
103 lines
2.7 KiB
C++
103 lines
2.7 KiB
C++
// This run stresses global reset happenning concurrently with everything else.
|
|
// RUN: %clangxx_tsan -O1 %s -o %t && %env_tsan_opts=flush_memory_ms=1:flush_symbolizer_ms=1:memory_limit_mb=1 %run %t 2>&1 | FileCheck %s --check-prefix=CHECK-NORACE
|
|
// This run stresses race reporting happenning concurrently with everything else.
|
|
// RUN: %clangxx_tsan -O1 %s -DRACE=1 -o %t && %env_tsan_opts=suppress_equal_stacks=0 %deflake %run %t | FileCheck %s --check-prefix=CHECK-RACE
|
|
#include "test.h"
|
|
#include <fcntl.h>
|
|
#include <string.h>
|
|
|
|
volatile long stop;
|
|
long atomic, read_only, racy;
|
|
int fds[2];
|
|
|
|
__attribute__((noinline)) void *SecondaryThread(void *x) {
|
|
__atomic_fetch_add(&atomic, 1, __ATOMIC_ACQ_REL);
|
|
return NULL;
|
|
}
|
|
|
|
void *Thread(void *x) {
|
|
const int me = (long)x;
|
|
volatile long sink = 0;
|
|
int fd = -1;
|
|
while (!stop) {
|
|
// If me == 0, we do all of the following,
|
|
// otherwise only 1 type of action.
|
|
if (me == 0 || me == 1) {
|
|
// just read the stop variable
|
|
}
|
|
if (me == 0 || me == 2) {
|
|
__atomic_store_n(&atomic, sink, __ATOMIC_RELEASE);
|
|
}
|
|
if (me == 0 || me == 3) {
|
|
sink += __atomic_fetch_add(&atomic, 1, __ATOMIC_ACQ_REL);
|
|
}
|
|
if (me == 0 || me == 4) {
|
|
SecondaryThread(NULL);
|
|
}
|
|
if (me == 0 || me == 5) {
|
|
write(fds[1], fds, 1);
|
|
}
|
|
if (me == 0 || me == 6) {
|
|
char buf[2];
|
|
read(fds[0], &buf, sizeof(buf));
|
|
}
|
|
if (me == 0 || me == 7) {
|
|
pthread_t th;
|
|
pthread_create(&th, NULL, SecondaryThread, NULL);
|
|
pthread_join(th, NULL);
|
|
}
|
|
if (me == 0 || me == 8) {
|
|
long buf;
|
|
memcpy(&buf, &read_only, sizeof(buf));
|
|
sink += buf;
|
|
}
|
|
if (me == 0 || me == 9) {
|
|
#if RACE
|
|
sink += racy++;
|
|
#else
|
|
sink += racy;
|
|
#endif
|
|
}
|
|
if (me == 0 || me == 10) {
|
|
fd = open("/dev/null", O_RDONLY);
|
|
if (fd != -1) {
|
|
close(fd);
|
|
fd = -1;
|
|
}
|
|
}
|
|
// If you add more actions, update kActions in main.
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
int main() {
|
|
ANNOTATE_BENIGN_RACE(stop);
|
|
if (pipe(fds))
|
|
exit((perror("pipe"), 1));
|
|
if (fcntl(fds[0], F_SETFL, O_NONBLOCK))
|
|
exit((perror("fcntl"), 1));
|
|
if (fcntl(fds[1], F_SETFL, O_NONBLOCK))
|
|
exit((perror("fcntl"), 1));
|
|
const int kActions = 11;
|
|
#if RACE
|
|
const int kMultiplier = 1;
|
|
#else
|
|
const int kMultiplier = 4;
|
|
#endif
|
|
pthread_t t[kActions * kMultiplier];
|
|
for (int i = 0; i < kActions * kMultiplier; i++)
|
|
pthread_create(&t[i], NULL, Thread, (void *)(long)(i % kActions));
|
|
sleep(5);
|
|
stop = 1;
|
|
for (int i = 0; i < kActions * kMultiplier; i++)
|
|
pthread_join(t[i], NULL);
|
|
fprintf(stderr, "DONE\n");
|
|
return 0;
|
|
}
|
|
|
|
// CHECK-NORACE-NOT: ThreadSanitizer:
|
|
// CHECK-NORACE: DONE
|
|
// CHECK-NORACE-NOT: ThreadSanitizer:
|
|
// CHECK-RACE: ThreadSanitizer: data race
|
|
// CHECK-RACE: DONE
|