diff options
author | Dimitry Andric <dim@FreeBSD.org> | 2017-06-01 20:58:59 +0000 |
---|---|---|
committer | Dimitry Andric <dim@FreeBSD.org> | 2017-06-01 20:58:59 +0000 |
commit | 06eabdc027f984611832945782f7c36800d0d397 (patch) | |
tree | 291f49ce58b030eafc7bec045dc0a1a29240bbb4 /test/sanitizer_common/TestCases/Linux/allocator_fork_no_hang.cc | |
parent | 224c1c721b03784d0da2af00884ea8d4eb7a1650 (diff) | |
download | src-06eabdc027f984611832945782f7c36800d0d397.tar.gz src-06eabdc027f984611832945782f7c36800d0d397.zip |
Vendor import of compiler-rt trunk r304460:vendor/compiler-rt/compiler-rt-trunk-r304460
Notes
Notes:
svn path=/vendor/compiler-rt/dist/; revision=319465
svn path=/vendor/compiler-rt/compiler-rt-trunk-r304460/; revision=319466; tag=vendor/compiler-rt/compiler-rt-trunk-r304460
Diffstat (limited to 'test/sanitizer_common/TestCases/Linux/allocator_fork_no_hang.cc')
-rw-r--r-- | test/sanitizer_common/TestCases/Linux/allocator_fork_no_hang.cc | 118 |
1 files changed, 118 insertions, 0 deletions
diff --git a/test/sanitizer_common/TestCases/Linux/allocator_fork_no_hang.cc b/test/sanitizer_common/TestCases/Linux/allocator_fork_no_hang.cc new file mode 100644 index 000000000000..d159d85ee2d6 --- /dev/null +++ b/test/sanitizer_common/TestCases/Linux/allocator_fork_no_hang.cc @@ -0,0 +1,118 @@ +// https://github.com/google/sanitizers/issues/774 +// Test that sanitizer allocator is fork-safe. +// Run a number of threads that perform memory allocation/deallocation, then fork +// and verify that malloc/free do not deadlock in the child process. + +// RUN: %clangxx -std=c++11 -O0 %s -o %t +// RUN: ASAN_OPTIONS=detect_leaks=0 %run %t 2>&1 | FileCheck %s + +// Fun fact: if test output is redirected to a file (as opposed to +// being piped directly to FileCheck), we may lose some "done"s due to +// a kernel bug: +// https://lkml.org/lkml/2014/2/17/324 + +// UNSUPPORTED: tsan + +// Flaky on PPC64. +// UNSUPPORTED: powerpc64-target-arch +// UNSUPPORTED: powerpc64le-target-arch + +#include <pthread.h> +#include <unistd.h> +#include <stdio.h> +#include <stdlib.h> +#include <sys/types.h> +#include <sys/wait.h> +#include <sys/time.h> +#include <signal.h> +#include <errno.h> + +int done; + +void *worker(void *arg) { + while (true) { + void *p = malloc(4); + if (__atomic_load_n(&done, __ATOMIC_RELAXED)) + return 0; + } + return 0; +} + +// Run through malloc/free in the child process. +// This can deadlock on allocator cache refilling. +void child() { + for (int i = 0; i < 10000; ++i) { + void *p = malloc(4); + } + write(2, "done\n", 5); +} + +void test() { + const int kThreads = 10; + pthread_t t[kThreads]; + for (int i = 0; i < kThreads; ++i) + pthread_create(&t[i], NULL, worker, (void*)(long)i); + usleep(100000); + pid_t pid = fork(); + if (pid) { + // parent + __atomic_store_n(&done, 1, __ATOMIC_RELAXED); + pid_t p; + while ((p = wait(NULL)) == -1) { } + } else { + // child + child(); + } +} + +int main() { + const int kChildren = 30; + for (int i = 0; i < kChildren; ++i) { + pid_t pid = fork(); + if (pid) { + // parent + } else { + test(); + exit(0); + } + } + + for (int i = 0; i < kChildren; ++i) { + pid_t p; + while ((p = wait(NULL)) == -1) { } + } + + return 0; +} + +// Expect 30 (== kChildren) "done" messages. +// CHECK: done +// CHECK: done +// CHECK: done +// CHECK: done +// CHECK: done +// CHECK: done +// CHECK: done +// CHECK: done +// CHECK: done +// CHECK: done +// CHECK: done +// CHECK: done +// CHECK: done +// CHECK: done +// CHECK: done +// CHECK: done +// CHECK: done +// CHECK: done +// CHECK: done +// CHECK: done +// CHECK: done +// CHECK: done +// CHECK: done +// CHECK: done +// CHECK: done +// CHECK: done +// CHECK: done +// CHECK: done +// CHECK: done +// CHECK: done |