diff --git a/compiler-rt/lib/asan/asan_rtl.cpp b/compiler-rt/lib/asan/asan_rtl.cpp --- a/compiler-rt/lib/asan/asan_rtl.cpp +++ b/compiler-rt/lib/asan/asan_rtl.cpp @@ -371,11 +371,6 @@ kHighShadowBeg > kMidMemEnd); } -static bool UNUSED __local_asan_dyninit = [] { - MaybeStartBackgroudThread(); - return false; -}(); - static void AsanInitInternal() { if (LIKELY(asan_inited)) return; SanitizerToolName = "AddressSanitizer"; diff --git a/compiler-rt/lib/dfsan/dfsan_allocator.cpp b/compiler-rt/lib/dfsan/dfsan_allocator.cpp --- a/compiler-rt/lib/dfsan/dfsan_allocator.cpp +++ b/compiler-rt/lib/dfsan/dfsan_allocator.cpp @@ -87,6 +87,12 @@ BufferedStackTrace stack; ReportAllocationSizeTooBig(size, max_malloc_size, &stack); } + if (UNLIKELY(IsRssLimitExceeded())) { + if (AllocatorMayReturnNull()) + return nullptr; + BufferedStackTrace stack; + ReportRssLimitExceeded(&stack); + } DFsanThread *t = GetCurrentThread(); void *allocated; if (t) { diff --git a/compiler-rt/lib/hwasan/hwasan_allocator.cpp b/compiler-rt/lib/hwasan/hwasan_allocator.cpp --- a/compiler-rt/lib/hwasan/hwasan_allocator.cpp +++ b/compiler-rt/lib/hwasan/hwasan_allocator.cpp @@ -132,6 +132,11 @@ } ReportAllocationSizeTooBig(orig_size, kMaxAllowedMallocSize, stack); } + if (UNLIKELY(IsRssLimitExceeded())) { + if (AllocatorMayReturnNull()) + return nullptr; + ReportRssLimitExceeded(stack); + } alignment = Max(alignment, kShadowAlignment); uptr size = TaggedSize(orig_size); diff --git a/compiler-rt/lib/lsan/lsan_allocator.cpp b/compiler-rt/lib/lsan/lsan_allocator.cpp --- a/compiler-rt/lib/lsan/lsan_allocator.cpp +++ b/compiler-rt/lib/lsan/lsan_allocator.cpp @@ -88,6 +88,11 @@ size = 1; if (size > max_malloc_size) return ReportAllocationSizeTooBig(size, stack); + if (UNLIKELY(IsRssLimitExceeded())) { + if (AllocatorMayReturnNull()) + return nullptr; + ReportRssLimitExceeded(&stack); + } void *p = allocator.Allocate(GetAllocatorCache(), size, alignment); if (UNLIKELY(!p)) { SetAllocatorOutOfMemory(); diff --git a/compiler-rt/lib/memprof/memprof_rtl.cpp b/compiler-rt/lib/memprof/memprof_rtl.cpp --- a/compiler-rt/lib/memprof/memprof_rtl.cpp +++ b/compiler-rt/lib/memprof/memprof_rtl.cpp @@ -133,11 +133,6 @@ CHECK(SHADOW_SCALE >= 3 && SHADOW_SCALE <= 7); } -static bool UNUSED __local_memprof_dyninit = [] { - MaybeStartBackgroudThread(); - return false; -}(); - static void MemprofInitInternal() { if (LIKELY(memprof_inited)) return; diff --git a/compiler-rt/lib/msan/msan_allocator.cpp b/compiler-rt/lib/msan/msan_allocator.cpp --- a/compiler-rt/lib/msan/msan_allocator.cpp +++ b/compiler-rt/lib/msan/msan_allocator.cpp @@ -160,6 +160,11 @@ } ReportAllocationSizeTooBig(size, max_malloc_size, stack); } + if (UNLIKELY(IsRssLimitExceeded())) { + if (AllocatorMayReturnNull()) + return nullptr; + ReportRssLimitExceeded(stack); + } MsanThread *t = GetCurrentThread(); void *allocated; if (t) { diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_common.h b/compiler-rt/lib/sanitizer_common/sanitizer_common.h --- a/compiler-rt/lib/sanitizer_common/sanitizer_common.h +++ b/compiler-rt/lib/sanitizer_common/sanitizer_common.h @@ -932,7 +932,6 @@ void *internal_start_thread(void *(*func)(void*), void *arg); void internal_join_thread(void *th); -void MaybeStartBackgroudThread(); // Make the compiler think that something is going on there. // Use this inside a loop that looks like memset/memcpy/etc to prevent the diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_common_libcdep.cpp b/compiler-rt/lib/sanitizer_common/sanitizer_common_libcdep.cpp --- a/compiler-rt/lib/sanitizer_common/sanitizer_common_libcdep.cpp +++ b/compiler-rt/lib/sanitizer_common/sanitizer_common_libcdep.cpp @@ -77,18 +77,20 @@ } } } -#endif -void MaybeStartBackgroudThread() { -#if (SANITIZER_LINUX || SANITIZER_NETBSD) && \ - !SANITIZER_GO // Need to implement/test on other platforms. +# pragma clang diagnostic push +// We avoid global-constructors to be sure that globals are ready when +// sanitizers need them. This can happend before global constructors executed. +// Here we don't mind if thread is started on later stages. +# pragma clang diagnostic ignored "-Wglobal-constructors" +static bool UNUSED local_dyninit = [] { // Start the background thread if one of the rss limits is given. if (!common_flags()->hard_rss_limit_mb && - !common_flags()->soft_rss_limit_mb && - !common_flags()->heap_profile) return; + !common_flags()->soft_rss_limit_mb && !common_flags()->heap_profile) + return false; if (!&real_pthread_create) { VPrintf(1, "%s: real_pthread_create undefined\n", SanitizerToolName); - return; // Can't spawn the thread anyway. + return false; // Can't spawn the thread anyway. } static bool started = false; @@ -96,8 +98,10 @@ started = true; internal_start_thread(BackgroundThread, nullptr); } + return true; +}(); +# pragma clang diagnostic pop #endif -} void WriteToSyslog(const char *msg) { InternalScopedString msg_copy; diff --git a/compiler-rt/lib/tsan/rtl/tsan_mman.cpp b/compiler-rt/lib/tsan/rtl/tsan_mman.cpp --- a/compiler-rt/lib/tsan/rtl/tsan_mman.cpp +++ b/compiler-rt/lib/tsan/rtl/tsan_mman.cpp @@ -192,6 +192,12 @@ GET_STACK_TRACE_FATAL(thr, pc); ReportAllocationSizeTooBig(sz, malloc_limit, &stack); } + if (UNLIKELY(IsRssLimitExceeded())) { + if (AllocatorMayReturnNull()) + return nullptr; + GET_STACK_TRACE_FATAL(thr, pc); + ReportRssLimitExceeded(&stack); + } void *p = allocator()->Allocate(&thr->proc()->alloc_cache, sz, align); if (UNLIKELY(!p)) { SetAllocatorOutOfMemory(); diff --git a/compiler-rt/test/sanitizer_common/TestCases/Linux/soft_rss_limit_mb_test.cpp b/compiler-rt/test/sanitizer_common/TestCases/Linux/soft_rss_limit_mb_test.cpp --- a/compiler-rt/test/sanitizer_common/TestCases/Linux/soft_rss_limit_mb_test.cpp +++ b/compiler-rt/test/sanitizer_common/TestCases/Linux/soft_rss_limit_mb_test.cpp @@ -3,17 +3,14 @@ // // Run with limit should fail: // RUN: %env_tool_opts=soft_rss_limit_mb=220:quarantine_size=1:allocator_may_return_null=1 %run %t 2>&1 | FileCheck %s -check-prefix=CHECK_MAY_RETURN_1 -// RUN: %env_tool_opts=soft_rss_limit_mb=220:quarantine_size=1:allocator_may_return_null=0 not %run %t 2>&1 | FileCheck %s -check-prefix=CHECK_MAY_RETURN_0 +// RUN: %env_tool_opts=soft_rss_limit_mb=220:quarantine_size=1:allocator_may_return_null=0 not %run %t 2>&1 | FileCheck %s -check-prefix=CHECK_MAY_RETURN_0 --implicit-check-not="returned null" // This run uses getrusage. We can only test getrusage when allocator_may_return_null=0 // because getrusage gives us max-rss, not current-rss. -// RUN: %env_tool_opts=soft_rss_limit_mb=220:quarantine_size=1:allocator_may_return_null=0:can_use_proc_maps_statm=0 not %run %t 2>&1 | FileCheck %s -check-prefix=CHECK_MAY_RETURN_0 +// RUN: %env_tool_opts=soft_rss_limit_mb=220:quarantine_size=1:allocator_may_return_null=0:can_use_proc_maps_statm=0 not %run %t 2>&1 | FileCheck %s -check-prefix=CHECK_MAY_RETURN_0 --implicit-check-not="returned null" // REQUIRES: stable-runtime -// FIXME: make it work for other sanitizers. -// XFAIL: lsan -// XFAIL: tsan -// XFAIL: msan +// Ubsan does not intercept pthread_create. // XFAIL: ubsan // https://github.com/google/sanitizers/issues/981 @@ -30,8 +27,8 @@ static char *allocs[kMaxNumAllocs]; int main() { - int num_allocs = kMaxNumAllocs / 4; - for (int i = 0; i < 3; i++, num_allocs *= 2) { + int num_allocs = kMaxNumAllocs / 16; + for (int i = 0; num_allocs <= kMaxNumAllocs; i++, num_allocs *= 2) { fprintf(stderr, "[%d] allocating %d times\n", i, num_allocs); int zero_results = 0; for (int j = 0; j < num_allocs; j++) { @@ -57,8 +54,8 @@ } } -// CHECK_MAY_RETURN_1: allocating 128 times -// CHECK_MAY_RETURN_1: Some of the malloc calls returned non-null: 128 +// CHECK_MAY_RETURN_1: allocating 32 times +// CHECK_MAY_RETURN_1: Some of the malloc calls returned non-null: // CHECK_MAY_RETURN_1: allocating 256 times // CHECK_MAY_RETURN_1: Some of the malloc calls returned null: // CHECK_MAY_RETURN_1: Some of the malloc calls returned non-null: @@ -66,7 +63,6 @@ // CHECK_MAY_RETURN_1: Some of the malloc calls returned null: // CHECK_MAY_RETURN_1: Some of the malloc calls returned non-null: -// CHECK_MAY_RETURN_0: allocating 128 times -// CHECK_MAY_RETURN_0: Some of the malloc calls returned non-null: 128 -// CHECK_MAY_RETURN_0: allocating 256 times +// CHECK_MAY_RETURN_0: allocating 32 times +// CHECK_MAY_RETURN_0: Some of the malloc calls returned non-null: // CHECK_MAY_RETURN_0: {{SUMMARY: .*Sanitizer: rss-limit-exceeded}} diff --git a/compiler-rt/test/sanitizer_common/TestCases/hard_rss_limit_mb_test.cpp b/compiler-rt/test/sanitizer_common/TestCases/hard_rss_limit_mb_test.cpp --- a/compiler-rt/test/sanitizer_common/TestCases/hard_rss_limit_mb_test.cpp +++ b/compiler-rt/test/sanitizer_common/TestCases/hard_rss_limit_mb_test.cpp @@ -7,15 +7,11 @@ // RUN: %env_tool_opts=hard_rss_limit_mb=100:can_use_proc_maps_statm=0 not %run %t 2>&1 | FileCheck %s // // Run w/o limit or with a large enough limit should pass: -// RUN: %env_tool_opts=hard_rss_limit_mb=1000 %run %t +// RUN: %env_tool_opts=hard_rss_limit_mb=4000 %run %t // RUN: %run %t // -// FIXME: make it work for other sanitizers. -// XFAIL: lsan -// XFAIL: tsan -// XFAIL: msan +// Ubsan does not intercept pthread_create. // XFAIL: ubsan - // UNSUPPORTED: freebsd, solaris, darwin #include