[sanitizer] Support IsRssLimitExceeded in all sanitizers
authorVitaly Buka <vitalybuka@google.com>
Thu, 2 Dec 2021 22:25:30 +0000 (14:25 -0800)
committerVitaly Buka <vitalybuka@google.com>
Fri, 3 Dec 2021 20:45:44 +0000 (12:45 -0800)
Reviewed By: kstoimenov

Differential Revision: https://reviews.llvm.org/D115000

compiler-rt/lib/asan/asan_rtl.cpp
compiler-rt/lib/dfsan/dfsan_allocator.cpp
compiler-rt/lib/hwasan/hwasan_allocator.cpp
compiler-rt/lib/lsan/lsan_allocator.cpp
compiler-rt/lib/memprof/memprof_rtl.cpp
compiler-rt/lib/msan/msan_allocator.cpp
compiler-rt/lib/sanitizer_common/sanitizer_common.h
compiler-rt/lib/sanitizer_common/sanitizer_common_libcdep.cpp
compiler-rt/lib/tsan/rtl/tsan_mman.cpp
compiler-rt/test/sanitizer_common/TestCases/Linux/soft_rss_limit_mb_test.cpp
compiler-rt/test/sanitizer_common/TestCases/hard_rss_limit_mb_test.cpp

index f13994e..9f2afd1 100644 (file)
@@ -371,11 +371,6 @@ void PrintAddressSpaceLayout() {
           kHighShadowBeg > kMidMemEnd);
 }
 
-static bool UNUSED __local_asan_dyninit = [] {
-  MaybeStartBackgroudThread();
-  return false;
-}();
-
 static void AsanInitInternal() {
   if (LIKELY(asan_inited)) return;
   SanitizerToolName = "AddressSanitizer";
index b2e9456..c50aee7 100644 (file)
@@ -87,6 +87,12 @@ static void *DFsanAllocate(uptr size, uptr alignment, bool zeroise) {
     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) {
index 9e17299..84e183f 100644 (file)
@@ -132,6 +132,11 @@ static void *HwasanAllocate(StackTrace *stack, uptr orig_size, uptr alignment,
     }
     ReportAllocationSizeTooBig(orig_size, kMaxAllowedMallocSize, stack);
   }
+  if (UNLIKELY(IsRssLimitExceeded())) {
+    if (AllocatorMayReturnNull())
+      return nullptr;
+    ReportRssLimitExceeded(stack);
+  }
 
   alignment = Max(alignment, kShadowAlignment);
   uptr size = TaggedSize(orig_size);
index 91e34eb..9af7bbb 100644 (file)
@@ -88,6 +88,11 @@ void *Allocate(const StackTrace &stack, uptr size, uptr alignment,
     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();
index f947a11..c3d1c5f 100644 (file)
@@ -133,11 +133,6 @@ void PrintAddressSpaceLayout() {
   CHECK(SHADOW_SCALE >= 3 && SHADOW_SCALE <= 7);
 }
 
-static bool UNUSED __local_memprof_dyninit = [] {
-  MaybeStartBackgroudThread();
-  return false;
-}();
-
 static void MemprofInitInternal() {
   if (LIKELY(memprof_inited))
     return;
index a97bd83..dc00645 100644 (file)
@@ -160,6 +160,11 @@ static void *MsanAllocate(StackTrace *stack, uptr size, uptr alignment,
     }
     ReportAllocationSizeTooBig(size, max_malloc_size, stack);
   }
+  if (UNLIKELY(IsRssLimitExceeded())) {
+    if (AllocatorMayReturnNull())
+      return nullptr;
+    ReportRssLimitExceeded(stack);
+  }
   MsanThread *t = GetCurrentThread();
   void *allocated;
   if (t) {
index db03a6b..945cdf3 100644 (file)
@@ -932,7 +932,6 @@ inline uptr GetPthreadDestructorIterations() {
 
 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
index 6a972a2..bab77b4 100644 (file)
@@ -77,11 +77,9 @@ void *BackgroundThread(void *arg) {
     }
   }
 }
-#endif
 
-void MaybeStartBackgroudThread() {
-#if (SANITIZER_LINUX || SANITIZER_NETBSD) && \
-    !SANITIZER_GO  // Need to implement/test on other platforms.
+static void MaybeStartBackgroudThread() {
+  // Need to implement/test on other platforms.
   // 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 &&
@@ -96,9 +94,19 @@ void MaybeStartBackgroudThread() {
     started = true;
     internal_start_thread(BackgroundThread, nullptr);
   }
-#endif
 }
 
+#  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 struct BackgroudThreadStarted {
+  BackgroudThreadStarted() { MaybeStartBackgroudThread(); }
+} background_thread_strarter UNUSED;
+#  pragma clang diagnostic pop
+#endif
+
 void WriteToSyslog(const char *msg) {
   InternalScopedString msg_copy;
   msg_copy.append("%s", msg);
index a31bebc..75044c3 100644 (file)
@@ -192,6 +192,12 @@ void *user_alloc_internal(ThreadState *thr, uptr pc, uptr sz, uptr align,
     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();
index f7d8b4d..1b17a31 100644 (file)
@@ -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 const int kAllocSize = 1 << 20;  // Large enough to go via mmap.
 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 @@ int main() {
   }
 }
 
-// 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 @@ int main() {
 // 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}}
index e01d416..64e80be 100644 (file)
@@ -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 <string.h>