From c9f1deeaa1e8e004372d4c5d50dd242674d904ef Mon Sep 17 00:00:00 2001 From: Vitaly Buka Date: Mon, 24 Jun 2024 23:42:55 -0700 Subject: =?UTF-8?q?[=F0=9D=98=80=F0=9D=97=BD=F0=9D=97=BF]=20changes=20to?= =?UTF-8?q?=20main=20this=20commit=20is=20based=20on?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Created using spr 1.3.4 [skip ci] --- compiler-rt/lib/asan/asan_interceptors.cpp | 2 +- compiler-rt/lib/hwasan/hwasan_interceptors.cpp | 2 +- compiler-rt/lib/lsan/lsan_interceptors.cpp | 2 +- compiler-rt/lib/memprof/memprof_interceptors.cpp | 2 +- compiler-rt/lib/msan/msan_interceptors.cpp | 2 +- .../sanitizer_common/sanitizer_common_libcdep.cpp | 4 +- .../lib/sanitizer_common/sanitizer_linux.cpp | 8 +-- compiler-rt/lib/sanitizer_common/sanitizer_posix.h | 28 ++++----- .../lib/tsan/rtl/tsan_interceptors_posix.cpp | 13 ++++- compiler-rt/lib/tsan/rtl/tsan_rtl.cpp | 4 ++ compiler-rt/test/tsan/Darwin/fork_deadlock.cpp | 66 ++++++++++++++++++++++ compiler-rt/test/tsan/Linux/fork_deadlock.cpp | 66 ---------------------- 12 files changed, 107 insertions(+), 92 deletions(-) create mode 100644 compiler-rt/test/tsan/Darwin/fork_deadlock.cpp delete mode 100644 compiler-rt/test/tsan/Linux/fork_deadlock.cpp diff --git a/compiler-rt/lib/asan/asan_interceptors.cpp b/compiler-rt/lib/asan/asan_interceptors.cpp index 6d1360e10497..f8f86a766b20 100644 --- a/compiler-rt/lib/asan/asan_interceptors.cpp +++ b/compiler-rt/lib/asan/asan_interceptors.cpp @@ -333,7 +333,7 @@ INTERCEPTOR(int, pthread_timedjoin_np, void *thread, void **ret, } # endif -DEFINE_REAL_PTHREAD_FUNCTIONS +DEFINE_INTERNAL_PTHREAD_FUNCTIONS #endif // ASAN_INTERCEPT_PTHREAD_CREATE #if ASAN_INTERCEPT_SWAPCONTEXT diff --git a/compiler-rt/lib/hwasan/hwasan_interceptors.cpp b/compiler-rt/lib/hwasan/hwasan_interceptors.cpp index 08ae435b8214..c10b5c158548 100644 --- a/compiler-rt/lib/hwasan/hwasan_interceptors.cpp +++ b/compiler-rt/lib/hwasan/hwasan_interceptors.cpp @@ -334,7 +334,7 @@ INTERCEPTOR(int, pthread_timedjoin_np, void *thread, void **ret, } # endif -DEFINE_REAL_PTHREAD_FUNCTIONS +DEFINE_INTERNAL_PTHREAD_FUNCTIONS DEFINE_REAL(int, vfork,) DECLARE_EXTERN_INTERCEPTOR_AND_WRAPPER(int, vfork,) diff --git a/compiler-rt/lib/lsan/lsan_interceptors.cpp b/compiler-rt/lib/lsan/lsan_interceptors.cpp index 1fd0010f9ea9..6df4b6865b37 100644 --- a/compiler-rt/lib/lsan/lsan_interceptors.cpp +++ b/compiler-rt/lib/lsan/lsan_interceptors.cpp @@ -525,7 +525,7 @@ INTERCEPTOR(int, pthread_timedjoin_np, void *thread, void **ret, # define LSAN_MAYBE_INTERCEPT_TIMEDJOIN # endif // SANITIZER_INTERCEPT_TIMEDJOIN -DEFINE_REAL_PTHREAD_FUNCTIONS +DEFINE_INTERNAL_PTHREAD_FUNCTIONS INTERCEPTOR(void, _exit, int status) { if (status == 0 && HasReportedLeaks()) status = common_flags()->exitcode; diff --git a/compiler-rt/lib/memprof/memprof_interceptors.cpp b/compiler-rt/lib/memprof/memprof_interceptors.cpp index a267f6d3d671..53ee4e953419 100644 --- a/compiler-rt/lib/memprof/memprof_interceptors.cpp +++ b/compiler-rt/lib/memprof/memprof_interceptors.cpp @@ -166,7 +166,7 @@ INTERCEPTOR(int, pthread_join, void *t, void **arg) { return REAL(pthread_join)(t, arg); } -DEFINE_REAL_PTHREAD_FUNCTIONS +DEFINE_INTERNAL_PTHREAD_FUNCTIONS INTERCEPTOR(char *, index, const char *string, int c) ALIAS(WRAP(strchr)); diff --git a/compiler-rt/lib/msan/msan_interceptors.cpp b/compiler-rt/lib/msan/msan_interceptors.cpp index 9abf24063325..789b739b4118 100644 --- a/compiler-rt/lib/msan/msan_interceptors.cpp +++ b/compiler-rt/lib/msan/msan_interceptors.cpp @@ -1226,7 +1226,7 @@ INTERCEPTOR(int, pthread_timedjoin_np, void *thread, void **retval, } #endif -DEFINE_REAL_PTHREAD_FUNCTIONS +DEFINE_INTERNAL_PTHREAD_FUNCTIONS extern char *tzname[2]; diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_common_libcdep.cpp b/compiler-rt/lib/sanitizer_common/sanitizer_common_libcdep.cpp index 7b74bb1a7e0f..a174ae7be991 100644 --- a/compiler-rt/lib/sanitizer_common/sanitizer_common_libcdep.cpp +++ b/compiler-rt/lib/sanitizer_common/sanitizer_common_libcdep.cpp @@ -87,8 +87,8 @@ void MaybeStartBackgroudThread() { if (!common_flags()->hard_rss_limit_mb && !common_flags()->soft_rss_limit_mb && !common_flags()->heap_profile) return; - if (!&real_pthread_create) { - VPrintf(1, "%s: real_pthread_create undefined\n", SanitizerToolName); + if (!&internal_pthread_create) { + VPrintf(1, "%s: internal_pthread_create undefined\n", SanitizerToolName); return; // Can't spawn the thread anyway. } diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_linux.cpp b/compiler-rt/lib/sanitizer_common/sanitizer_linux.cpp index bf2002b6b3de..12df3ef73da4 100644 --- a/compiler-rt/lib/sanitizer_common/sanitizer_linux.cpp +++ b/compiler-rt/lib/sanitizer_common/sanitizer_linux.cpp @@ -1845,18 +1845,18 @@ HandleSignalMode GetHandleSignalMode(int signum) { # if !SANITIZER_GO void *internal_start_thread(void *(*func)(void *arg), void *arg) { - if (&real_pthread_create == 0) + if (&internal_pthread_create == 0) return nullptr; // Start the thread with signals blocked, otherwise it can steal user signals. ScopedBlockSignals block(nullptr); void *th; - real_pthread_create(&th, nullptr, func, arg); + internal_pthread_create(&th, nullptr, func, arg); return th; } void internal_join_thread(void *th) { - if (&real_pthread_join) - real_pthread_join(th, nullptr); + if (&internal_pthread_join) + internal_pthread_join(th, nullptr); } # else void *internal_start_thread(void *(*func)(void *), void *arg) { return 0; } diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_posix.h b/compiler-rt/lib/sanitizer_common/sanitizer_posix.h index c5811dffea94..14617e4771be 100644 --- a/compiler-rt/lib/sanitizer_common/sanitizer_posix.h +++ b/compiler-rt/lib/sanitizer_common/sanitizer_posix.h @@ -74,21 +74,21 @@ int internal_sysctlbyname(const char *sname, void *oldp, uptr *oldlenp, // These functions call appropriate pthread_ functions directly, bypassing // the interceptor. They are weak and may not be present in some tools. SANITIZER_WEAK_ATTRIBUTE -int real_pthread_create(void *th, void *attr, void *(*callback)(void *), - void *param); +int internal_pthread_create(void *th, void *attr, void *(*callback)(void *), + void *param); SANITIZER_WEAK_ATTRIBUTE -int real_pthread_join(void *th, void **ret); - -#define DEFINE_REAL_PTHREAD_FUNCTIONS \ - namespace __sanitizer { \ - int real_pthread_create(void *th, void *attr, void *(*callback)(void *), \ - void *param) { \ - return REAL(pthread_create)(th, attr, callback, param); \ - } \ - int real_pthread_join(void *th, void **ret) { \ - return REAL(pthread_join(th, ret)); \ - } \ - } // namespace __sanitizer +int internal_pthread_join(void *th, void **ret); + +# define DEFINE_INTERNAL_PTHREAD_FUNCTIONS \ + namespace __sanitizer { \ + int internal_pthread_create(void *th, void *attr, \ + void *(*callback)(void *), void *param) { \ + return REAL(pthread_create)(th, attr, callback, param); \ + } \ + int internal_pthread_join(void *th, void **ret) { \ + return REAL(pthread_join(th, ret)); \ + } \ + } // namespace __sanitizer int internal_pthread_attr_getstack(void *attr, void **addr, uptr *size); diff --git a/compiler-rt/lib/tsan/rtl/tsan_interceptors_posix.cpp b/compiler-rt/lib/tsan/rtl/tsan_interceptors_posix.cpp index 94adea777caf..034ae3d322b5 100644 --- a/compiler-rt/lib/tsan/rtl/tsan_interceptors_posix.cpp +++ b/compiler-rt/lib/tsan/rtl/tsan_interceptors_posix.cpp @@ -1088,7 +1088,18 @@ TSAN_INTERCEPTOR(int, pthread_join, void *th, void **ret) { return res; } -DEFINE_REAL_PTHREAD_FUNCTIONS +// DEFINE_INTERNAL_PTHREAD_FUNCTIONS +namespace __sanitizer { +int internal_pthread_create(void *th, void *attr, void *(*callback)(void *), + void *param) { + ScopedIgnoreInterceptors ignore; + return REAL(pthread_create)(th, attr, callback, param); +} +int internal_pthread_join(void *th, void **ret) { + ScopedIgnoreInterceptors ignore; + return REAL(pthread_join(th, ret)); +} +} // namespace __sanitizer TSAN_INTERCEPTOR(int, pthread_detach, void *th) { SCOPED_INTERCEPTOR_RAW(pthread_detach, th); diff --git a/compiler-rt/lib/tsan/rtl/tsan_rtl.cpp b/compiler-rt/lib/tsan/rtl/tsan_rtl.cpp index fd9441dfcb53..2d5992b703a6 100644 --- a/compiler-rt/lib/tsan/rtl/tsan_rtl.cpp +++ b/compiler-rt/lib/tsan/rtl/tsan_rtl.cpp @@ -35,8 +35,10 @@ extern "C" void __tsan_resume() { __tsan_resumed = 1; } +#if SANITIZER_APPLE SANITIZER_WEAK_DEFAULT_IMPL void __tsan_test_only_on_fork() {} +#endif namespace __tsan { @@ -828,7 +830,9 @@ void ForkBefore(ThreadState* thr, uptr pc) SANITIZER_NO_THREAD_SAFETY_ANALYSIS { // Disables memory write in OnUserAlloc/Free. thr->ignore_reads_and_writes++; +# if SANITIZER_APPLE __tsan_test_only_on_fork(); +# endif } static void ForkAfter(ThreadState* thr) SANITIZER_NO_THREAD_SAFETY_ANALYSIS { diff --git a/compiler-rt/test/tsan/Darwin/fork_deadlock.cpp b/compiler-rt/test/tsan/Darwin/fork_deadlock.cpp new file mode 100644 index 000000000000..952507032df6 --- /dev/null +++ b/compiler-rt/test/tsan/Darwin/fork_deadlock.cpp @@ -0,0 +1,66 @@ +// RUN: %clangxx_tsan -O1 %s -o %t && %env_tsan_opts=atexit_sleep_ms=0 %run %t 2>&1 | FileCheck %s + +// This test models what happens on Mac when fork +// calls malloc/free inside of our atfork callbacks. +// and ensures that we don't deadlock on malloc/free calls. + +#include "../test.h" +#include "syscall.h" +#include +#include +#include +#include + +// disable_sanitizer_instrumentation on __tsan_test_only_on_fork is not +// transitive, so we must apply it here as well. +// Instrumenting alloc_free_blocks() will result in deadlocks in TSan. +__attribute__((disable_sanitizer_instrumentation)) void alloc_free_blocks() { + // Allocate a bunch of blocks to drain local allocator cache + // and provoke it to lock allocator global mutexes. + const int kBlocks = 1000; + void *blocks[kBlocks]; + for (int i = 0; i < kBlocks; i++) { + void *p = malloc(10); + *(volatile char *)p = 0; + blocks[i] = p; + } + for (int i = 0; i < kBlocks; i++) + free(blocks[i]); +} + +__attribute__((disable_sanitizer_instrumentation)) extern "C" void +__tsan_test_only_on_fork() { + const char *msg = "__tsan_test_only_on_fork\n"; + write(2, msg, strlen(msg)); + alloc_free_blocks(); +} + +static void *background(void *p) { + for (;;) + alloc_free_blocks(); + return 0; +} + +int main() { + pthread_t th; + pthread_create(&th, 0, background, 0); + pthread_detach(th); + for (int i = 0; i < 10; i++) { + int pid = myfork(); + if (pid < 0) { + fprintf(stderr, "failed to fork (%d)\n", errno); + exit(1); + } + if (pid == 0) { + // child + exit(0); + } + // parent + while (wait(0) < 0) { + } + } + fprintf(stderr, "DONE\n"); +} + +// CHECK: __tsan_test_only_on_fork +// CHECK: DONE diff --git a/compiler-rt/test/tsan/Linux/fork_deadlock.cpp b/compiler-rt/test/tsan/Linux/fork_deadlock.cpp deleted file mode 100644 index 952507032df6..000000000000 --- a/compiler-rt/test/tsan/Linux/fork_deadlock.cpp +++ /dev/null @@ -1,66 +0,0 @@ -// RUN: %clangxx_tsan -O1 %s -o %t && %env_tsan_opts=atexit_sleep_ms=0 %run %t 2>&1 | FileCheck %s - -// This test models what happens on Mac when fork -// calls malloc/free inside of our atfork callbacks. -// and ensures that we don't deadlock on malloc/free calls. - -#include "../test.h" -#include "syscall.h" -#include -#include -#include -#include - -// disable_sanitizer_instrumentation on __tsan_test_only_on_fork is not -// transitive, so we must apply it here as well. -// Instrumenting alloc_free_blocks() will result in deadlocks in TSan. -__attribute__((disable_sanitizer_instrumentation)) void alloc_free_blocks() { - // Allocate a bunch of blocks to drain local allocator cache - // and provoke it to lock allocator global mutexes. - const int kBlocks = 1000; - void *blocks[kBlocks]; - for (int i = 0; i < kBlocks; i++) { - void *p = malloc(10); - *(volatile char *)p = 0; - blocks[i] = p; - } - for (int i = 0; i < kBlocks; i++) - free(blocks[i]); -} - -__attribute__((disable_sanitizer_instrumentation)) extern "C" void -__tsan_test_only_on_fork() { - const char *msg = "__tsan_test_only_on_fork\n"; - write(2, msg, strlen(msg)); - alloc_free_blocks(); -} - -static void *background(void *p) { - for (;;) - alloc_free_blocks(); - return 0; -} - -int main() { - pthread_t th; - pthread_create(&th, 0, background, 0); - pthread_detach(th); - for (int i = 0; i < 10; i++) { - int pid = myfork(); - if (pid < 0) { - fprintf(stderr, "failed to fork (%d)\n", errno); - exit(1); - } - if (pid == 0) { - // child - exit(0); - } - // parent - while (wait(0) < 0) { - } - } - fprintf(stderr, "DONE\n"); -} - -// CHECK: __tsan_test_only_on_fork -// CHECK: DONE -- cgit v1.2.3