[compiler-rt] r334843 - [scudo] Add verbose failures in place of CHECK(0)

Kostya Kortchinsky via llvm-commits llvm-commits at lists.llvm.org
Fri Jun 15 09:45:19 PDT 2018


Author: cryptoad
Date: Fri Jun 15 09:45:19 2018
New Revision: 334843

URL: http://llvm.org/viewvc/llvm-project?rev=334843&view=rev
Log:
[scudo] Add verbose failures in place of CHECK(0)

Summary:
The current `FailureHandler` mechanism was fairly opaque with regard to the
failure reason due to using `CHECK(0)`. Scudo is a bit different from the other
Sanitizers as it prefers to avoid spurious processing in its failure path. So
we just `dieWithMessage` using a somewhat explicit string.

Adapted the tests for the new strings.

While this takes care of the `OnBadRequest` & `OnOOM` failures, the next step
is probably to migrate the other Scudo failures in the same failes (header
corruption, invalid state and so on).

Reviewers: alekseyshl

Reviewed By: alekseyshl

Subscribers: filcab, mgorny, delcypher, #sanitizers, llvm-commits

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

Added:
    compiler-rt/trunk/lib/scudo/scudo_errors.cpp
    compiler-rt/trunk/lib/scudo/scudo_errors.h
Modified:
    compiler-rt/trunk/lib/scudo/CMakeLists.txt
    compiler-rt/trunk/lib/scudo/scudo_allocator.cpp
    compiler-rt/trunk/lib/scudo/scudo_allocator_secondary.h
    compiler-rt/trunk/lib/scudo/scudo_new_delete.cpp
    compiler-rt/trunk/test/scudo/aligned-new.cpp
    compiler-rt/trunk/test/scudo/memalign.c
    compiler-rt/trunk/test/scudo/sizes.cpp
    compiler-rt/trunk/test/scudo/valloc.c

Modified: compiler-rt/trunk/lib/scudo/CMakeLists.txt
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/scudo/CMakeLists.txt?rev=334843&r1=334842&r2=334843&view=diff
==============================================================================
--- compiler-rt/trunk/lib/scudo/CMakeLists.txt (original)
+++ compiler-rt/trunk/lib/scudo/CMakeLists.txt Fri Jun 15 09:45:19 2018
@@ -36,6 +36,7 @@ endif()
 set(SCUDO_SOURCES
   scudo_allocator.cpp
   scudo_crc32.cpp
+  scudo_errors.cpp
   scudo_flags.cpp
   scudo_malloc.cpp
   scudo_termination.cpp

Modified: compiler-rt/trunk/lib/scudo/scudo_allocator.cpp
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/scudo/scudo_allocator.cpp?rev=334843&r1=334842&r2=334843&view=diff
==============================================================================
--- compiler-rt/trunk/lib/scudo/scudo_allocator.cpp (original)
+++ compiler-rt/trunk/lib/scudo/scudo_allocator.cpp Fri Jun 15 09:45:19 2018
@@ -16,6 +16,7 @@
 
 #include "scudo_allocator.h"
 #include "scudo_crc32.h"
+#include "scudo_errors.h"
 #include "scudo_flags.h"
 #include "scudo_interface_internal.h"
 #include "scudo_tsd.h"
@@ -224,8 +225,6 @@ struct ScudoAllocator {
   static const uptr MaxAllowedMallocSize =
       FIRST_32_SECOND_64(2UL << 30, 1ULL << 40);
 
-  typedef ReturnNullOrDieOnFailure FailureHandler;
-
   ScudoBackendAllocator BackendAllocator;
   ScudoQuarantine AllocatorQuarantine;
 
@@ -360,24 +359,30 @@ struct ScudoAllocator {
   void *allocate(uptr Size, uptr Alignment, AllocType Type,
                  bool ForceZeroContents = false) {
     initThreadMaybe();
-    if (UNLIKELY(Alignment > MaxAlignment))
-      return FailureHandler::OnBadRequest();
+    if (UNLIKELY(Alignment > MaxAlignment)) {
+      if (AllocatorMayReturnNull())
+        return nullptr;
+      reportAllocationAlignmentTooBig(Alignment, MaxAlignment);
+    }
     if (UNLIKELY(Alignment < MinAlignment))
       Alignment = MinAlignment;
-    if (UNLIKELY(Size >= MaxAllowedMallocSize))
-      return FailureHandler::OnBadRequest();
-    if (UNLIKELY(Size == 0))
-      Size = 1;
 
-    const uptr NeededSize = RoundUpTo(Size, MinAlignment) +
+    const uptr NeededSize = RoundUpTo(Size ? Size : 1, MinAlignment) +
         Chunk::getHeaderSize();
     const uptr AlignedSize = (Alignment > MinAlignment) ?
         NeededSize + (Alignment - Chunk::getHeaderSize()) : NeededSize;
-    if (UNLIKELY(AlignedSize >= MaxAllowedMallocSize))
-      return FailureHandler::OnBadRequest();
+    if (UNLIKELY(Size >= MaxAllowedMallocSize) ||
+        UNLIKELY(AlignedSize >= MaxAllowedMallocSize)) {
+      if (AllocatorMayReturnNull())
+        return nullptr;
+      reportAllocationSizeTooBig(Size, AlignedSize, MaxAllowedMallocSize);
+    }
 
-    if (CheckRssLimit && UNLIKELY(isRssLimitExceeded()))
-      return FailureHandler::OnOOM();
+    if (CheckRssLimit && UNLIKELY(isRssLimitExceeded())) {
+      if (AllocatorMayReturnNull())
+        return nullptr;
+      reportRssLimitExceeded();
+    }
 
     // Primary and Secondary backed allocations have a different treatment. We
     // deal with alignment requirements of Primary serviced allocations here,
@@ -398,8 +403,12 @@ struct ScudoAllocator {
       ClassId = 0;
       BackendPtr = BackendAllocator.allocateSecondary(BackendSize, Alignment);
     }
-    if (UNLIKELY(!BackendPtr))
-      return FailureHandler::OnOOM();
+    if (UNLIKELY(!BackendPtr)) {
+      SetAllocatorOutOfMemory();
+      if (AllocatorMayReturnNull())
+        return nullptr;
+      reportOutOfMemory(Size);
+    }
 
     // If requested, we will zero out the entire contents of the returned chunk.
     if ((ForceZeroContents || ZeroContents) && ClassId)
@@ -573,8 +582,11 @@ struct ScudoAllocator {
 
   void *calloc(uptr NMemB, uptr Size) {
     initThreadMaybe();
-    if (UNLIKELY(CheckForCallocOverflow(NMemB, Size)))
-      return FailureHandler::OnBadRequest();
+    if (UNLIKELY(CheckForCallocOverflow(NMemB, Size))) {
+      if (AllocatorMayReturnNull())
+        return nullptr;
+      reportCallocOverflow(NMemB, Size);
+    }
     return allocate(NMemB * Size, MinAlignment, FromMalloc, true);
   }
 
@@ -591,9 +603,9 @@ struct ScudoAllocator {
     return stats[StatType];
   }
 
-  void *handleBadRequest() {
+  bool canReturnNull() {
     initThreadMaybe();
-    return FailureHandler::OnBadRequest();
+    return AllocatorMayReturnNull();
   }
 
   void setRssLimit(uptr LimitMb, bool HardLimit) {
@@ -632,7 +644,9 @@ void ScudoTSD::commitBack() {
 void *scudoAllocate(uptr Size, uptr Alignment, AllocType Type) {
   if (Alignment && UNLIKELY(!IsPowerOfTwo(Alignment))) {
     errno = EINVAL;
-    return Instance.handleBadRequest();
+    if (Instance.canReturnNull())
+      return nullptr;
+    reportAllocationAlignmentNotPowerOfTwo(Alignment);
   }
   return SetErrnoOnNull(Instance.allocate(Size, Alignment, Type));
 }
@@ -664,7 +678,9 @@ void *scudoPvalloc(uptr Size) {
   uptr PageSize = GetPageSizeCached();
   if (UNLIKELY(CheckForPvallocOverflow(Size, PageSize))) {
     errno = ENOMEM;
-    return Instance.handleBadRequest();
+    if (Instance.canReturnNull())
+      return nullptr;
+    reportPvallocOverflow(Size);
   }
   // pvalloc(0) should allocate one page.
   Size = Size ? RoundUpTo(Size, PageSize) : PageSize;
@@ -673,7 +689,8 @@ void *scudoPvalloc(uptr Size) {
 
 int scudoPosixMemalign(void **MemPtr, uptr Alignment, uptr Size) {
   if (UNLIKELY(!CheckPosixMemalignAlignment(Alignment))) {
-    Instance.handleBadRequest();
+    if (!Instance.canReturnNull())
+      reportInvalidPosixMemalignAlignment(Alignment);
     return EINVAL;
   }
   void *Ptr = Instance.allocate(Size, Alignment, FromMemalign);
@@ -686,7 +703,9 @@ int scudoPosixMemalign(void **MemPtr, up
 void *scudoAlignedAlloc(uptr Alignment, uptr Size) {
   if (UNLIKELY(!CheckAlignedAllocAlignmentAndSize(Alignment, Size))) {
     errno = EINVAL;
-    return Instance.handleBadRequest();
+    if (Instance.canReturnNull())
+      return nullptr;
+    reportInvalidAlignedAllocAlignment(Size, Alignment);
   }
   return SetErrnoOnNull(Instance.allocate(Size, Alignment, FromMalloc));
 }

Modified: compiler-rt/trunk/lib/scudo/scudo_allocator_secondary.h
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/scudo/scudo_allocator_secondary.h?rev=334843&r1=334842&r2=334843&view=diff
==============================================================================
--- compiler-rt/trunk/lib/scudo/scudo_allocator_secondary.h (original)
+++ compiler-rt/trunk/lib/scudo/scudo_allocator_secondary.h Fri Jun 15 09:45:19 2018
@@ -87,7 +87,7 @@ class ScudoLargeMmapAllocator {
     ReservedAddressRange AddressRange;
     uptr ReservedBeg = AddressRange.Init(ReservedSize, SecondaryAllocatorName);
     if (UNLIKELY(ReservedBeg == ~static_cast<uptr>(0)))
-      return ReturnNullOrDieOnFailure::OnOOM();
+      return nullptr;
     // A page-aligned pointer is assumed after that, so check it now.
     DCHECK(IsAligned(ReservedBeg, PageSize));
     uptr ReservedEnd = ReservedBeg + ReservedSize;

Added: compiler-rt/trunk/lib/scudo/scudo_errors.cpp
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/scudo/scudo_errors.cpp?rev=334843&view=auto
==============================================================================
--- compiler-rt/trunk/lib/scudo/scudo_errors.cpp (added)
+++ compiler-rt/trunk/lib/scudo/scudo_errors.cpp Fri Jun 15 09:45:19 2018
@@ -0,0 +1,77 @@
+//===-- scudo_errors.cpp ----------------------------------------*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+///
+/// Verbose termination functions.
+///
+//===----------------------------------------------------------------------===//
+
+#include "scudo_utils.h"
+
+#include "sanitizer_common/sanitizer_flags.h"
+
+namespace __scudo {
+
+void NORETURN reportCallocOverflow(uptr Count, uptr Size) {
+  dieWithMessage("calloc parameters overflow: count * size (%zd * %zd) cannot "
+      "be represented with type size_t\n", Count, Size);
+}
+
+void NORETURN reportPvallocOverflow(uptr Size) {
+  dieWithMessage("pvalloc parameters overflow: size 0x%zx rounded up to system "
+      "page size 0x%zx cannot be represented in type size_t\n", Size,
+      GetPageSizeCached());
+}
+
+void NORETURN reportAllocationAlignmentTooBig(uptr Alignment,
+                                              uptr MaxAlignment) {
+  dieWithMessage("invalid allocation alignment: %zd exceeds maximum supported "
+      "allocation of %zd\n", Alignment, MaxAlignment);
+}
+
+void NORETURN reportAllocationAlignmentNotPowerOfTwo(uptr Alignment) {
+  dieWithMessage("invalid allocation alignment: %zd, alignment must be a power "
+      "of two\n", Alignment);
+}
+
+void NORETURN reportInvalidPosixMemalignAlignment(uptr Alignment) {
+  dieWithMessage("invalid alignment requested in posix_memalign: %zd, alignment"
+      " must be a power of two and a multiple of sizeof(void *) == %zd\n",
+      Alignment, sizeof(void *));  // NOLINT
+}
+
+void NORETURN reportInvalidAlignedAllocAlignment(uptr Size, uptr Alignment) {
+#if SANITIZER_POSIX
+  dieWithMessage("invalid alignment requested in aligned_alloc: %zd, alignment "
+      "must be a power of two and the requested size 0x%zx must be a multiple "
+      "of alignment\n", Alignment, Size);
+#else
+  dieWithMessage("invalid alignment requested in aligned_alloc: %zd, the "
+      "requested size 0x%zx must be a multiple of alignment\n", Alignment,
+      Size);
+#endif
+}
+
+void NORETURN reportAllocationSizeTooBig(uptr UserSize, uptr TotalSize,
+                                         uptr MaxSize) {
+  dieWithMessage("requested allocation size 0x%zx (0x%zx after adjustments) "
+      "exceeds maximum supported size of 0x%zx\n", UserSize, TotalSize,
+      MaxSize);
+}
+
+void NORETURN reportRssLimitExceeded() {
+  dieWithMessage("specified RSS limit exceeded, currently set to "
+      "soft_rss_limit_mb=%zd\n", common_flags()->soft_rss_limit_mb);
+}
+
+void NORETURN reportOutOfMemory(uptr RequestedSize) {
+  dieWithMessage("allocator is out of memory trying to allocate 0x%zx bytes\n",
+                 RequestedSize);
+}
+
+}  // namespace __scudo

Added: compiler-rt/trunk/lib/scudo/scudo_errors.h
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/scudo/scudo_errors.h?rev=334843&view=auto
==============================================================================
--- compiler-rt/trunk/lib/scudo/scudo_errors.h (added)
+++ compiler-rt/trunk/lib/scudo/scudo_errors.h Fri Jun 15 09:45:19 2018
@@ -0,0 +1,35 @@
+//===-- scudo_errors.h ------------------------------------------*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+///
+/// Header for scudo_errors.cpp.
+///
+//===----------------------------------------------------------------------===//
+
+#ifndef SCUDO_ERRORS_H_
+#define SCUDO_ERRORS_H_
+
+#include "sanitizer_common/sanitizer_internal_defs.h"
+
+namespace __scudo {
+
+void NORETURN reportCallocOverflow(uptr Count, uptr Size);
+void NORETURN reportPvallocOverflow(uptr Size);
+void NORETURN reportAllocationAlignmentTooBig(uptr Alignment,
+                                              uptr MaxAlignment);
+void NORETURN reportAllocationAlignmentNotPowerOfTwo(uptr Alignment);
+void NORETURN reportInvalidPosixMemalignAlignment(uptr Alignment);
+void NORETURN reportInvalidAlignedAllocAlignment(uptr Size, uptr Alignment);
+void NORETURN reportAllocationSizeTooBig(uptr UserSize, uptr TotalSize,
+                                         uptr MaxSize);
+void NORETURN reportRssLimitExceeded();
+void NORETURN reportOutOfMemory(uptr RequestedSize);
+
+}  // namespace __scudo
+
+#endif  // SCUDO_ERRORS_H_

Modified: compiler-rt/trunk/lib/scudo/scudo_new_delete.cpp
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/scudo/scudo_new_delete.cpp?rev=334843&r1=334842&r2=334843&view=diff
==============================================================================
--- compiler-rt/trunk/lib/scudo/scudo_new_delete.cpp (original)
+++ compiler-rt/trunk/lib/scudo/scudo_new_delete.cpp Fri Jun 15 09:45:19 2018
@@ -12,6 +12,7 @@
 //===----------------------------------------------------------------------===//
 
 #include "scudo_allocator.h"
+#include "scudo_errors.h"
 
 #include "interception/interception.h"
 
@@ -30,7 +31,7 @@ enum class align_val_t: size_t {};
 // TODO(alekseys): throw std::bad_alloc instead of dying on OOM.
 #define OPERATOR_NEW_BODY_ALIGN(Type, Align, NoThrow)              \
   void *Ptr = scudoAllocate(size, static_cast<uptr>(Align), Type); \
-  if (!NoThrow && UNLIKELY(!Ptr)) DieOnFailure::OnOOM();           \
+  if (!NoThrow && UNLIKELY(!Ptr)) reportOutOfMemory(size);         \
   return Ptr;
 #define OPERATOR_NEW_BODY(Type, NoThrow) \
   OPERATOR_NEW_BODY_ALIGN(Type, 0, NoThrow)

Modified: compiler-rt/trunk/test/scudo/aligned-new.cpp
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/test/scudo/aligned-new.cpp?rev=334843&r1=334842&r2=334843&view=diff
==============================================================================
--- compiler-rt/trunk/test/scudo/aligned-new.cpp (original)
+++ compiler-rt/trunk/test/scudo/aligned-new.cpp Fri Jun 15 09:45:19 2018
@@ -1,6 +1,7 @@
 // RUN: %clangxx_scudo -std=c++1z -faligned-allocation %s -o %t
-// RUN:                                             %run %t valid   2>&1
-// RUN: %env_scudo_opts=allocator_may_return_null=1 %run %t invalid 2>&1
+// RUN:                                                 %run %t valid   2>&1
+// RUN: %env_scudo_opts=allocator_may_return_null=1     %run %t invalid 2>&1
+// RUN: %env_scudo_opts=allocator_may_return_null=0 not %run %t invalid 2>&1 | FileCheck %s
 
 // Tests that the C++17 aligned new/delete operators are working as expected.
 // Currently we do not check the consistency of the alignment on deallocation,
@@ -77,6 +78,7 @@ int main(int argc, char **argv) {
     const size_t alignment = (1U << 8) - 1;
     void *p = operator new(1, static_cast<std::align_val_t>(alignment),
                            std::nothrow);
+    // CHECK: Scudo ERROR: invalid allocation alignment
     assert(!p);
   }
 

Modified: compiler-rt/trunk/test/scudo/memalign.c
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/test/scudo/memalign.c?rev=334843&r1=334842&r2=334843&view=diff
==============================================================================
--- compiler-rt/trunk/test/scudo/memalign.c (original)
+++ compiler-rt/trunk/test/scudo/memalign.c Fri Jun 15 09:45:19 2018
@@ -1,6 +1,6 @@
 // RUN: %clang_scudo %s -o %t
 // RUN:                                                 %run %t valid       2>&1
-// RUN:                                             not %run %t invalid     2>&1
+// RUN:                                             not %run %t invalid     2>&1 | FileCheck --check-prefix=CHECK-align %s
 // RUN: %env_scudo_opts=allocator_may_return_null=1     %run %t invalid     2>&1
 // RUN:                                             not %run %t double-free 2>&1 | FileCheck --check-prefix=CHECK-double-free %s
 // RUN: %env_scudo_opts=DeallocationTypeMismatch=1  not %run %t realloc     2>&1 | FileCheck --check-prefix=CHECK-realloc %s
@@ -66,6 +66,7 @@ int main(int argc, char **argv)
   if (!strcmp(argv[1], "invalid")) {
     // Alignment is not a power of 2.
     p = memalign(alignment - 1, size);
+    // CHECK-align: Scudo ERROR: invalid allocation alignment
     assert(!p);
     // Size is not a multiple of alignment.
     p = aligned_alloc(alignment, size >> 1);

Modified: compiler-rt/trunk/test/scudo/sizes.cpp
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/test/scudo/sizes.cpp?rev=334843&r1=334842&r2=334843&view=diff
==============================================================================
--- compiler-rt/trunk/test/scudo/sizes.cpp (original)
+++ compiler-rt/trunk/test/scudo/sizes.cpp Fri Jun 15 09:45:19 2018
@@ -1,11 +1,11 @@
 // RUN: %clangxx_scudo %s -lstdc++ -o %t
-// RUN: %env_scudo_opts=allocator_may_return_null=0 not %run %t malloc 2>&1 | FileCheck %s
+// RUN: %env_scudo_opts=allocator_may_return_null=0 not %run %t malloc 2>&1      | FileCheck %s --check-prefix=CHECK-max
 // RUN: %env_scudo_opts=allocator_may_return_null=1     %run %t malloc 2>&1
-// RUN: %env_scudo_opts=allocator_may_return_null=0 not %run %t calloc 2>&1 | FileCheck %s
+// RUN: %env_scudo_opts=allocator_may_return_null=0 not %run %t calloc 2>&1      | FileCheck %s --check-prefix=CHECK-calloc
 // RUN: %env_scudo_opts=allocator_may_return_null=1     %run %t calloc 2>&1
-// RUN: %env_scudo_opts=allocator_may_return_null=0 not %run %t new 2>&1 | FileCheck %s
-// RUN: %env_scudo_opts=allocator_may_return_null=1 not %run %t new 2>&1 | FileCheck %s
-// RUN: %env_scudo_opts=allocator_may_return_null=0 not %run %t new-nothrow 2>&1 | FileCheck %s
+// RUN: %env_scudo_opts=allocator_may_return_null=0 not %run %t new 2>&1         | FileCheck %s --check-prefix=CHECK-max
+// RUN: %env_scudo_opts=allocator_may_return_null=1 not %run %t new 2>&1         | FileCheck %s --check-prefix=CHECK-oom
+// RUN: %env_scudo_opts=allocator_may_return_null=0 not %run %t new-nothrow 2>&1 | FileCheck %s --check-prefix=CHECK-max
 // RUN: %env_scudo_opts=allocator_may_return_null=1     %run %t new-nothrow 2>&1
 // RUN:                                                 %run %t usable 2>&1
 
@@ -70,4 +70,6 @@ int main(int argc, char **argv) {
   return 0;
 }
 
-// CHECK: allocator is terminating the process
+// CHECK-max: {{Scudo ERROR: requested allocation size .* exceeds maximum supported size}}
+// CHECK-oom: Scudo ERROR: allocator is out of memory
+// CHECK-calloc: Scudo ERROR: calloc parameters overflow

Modified: compiler-rt/trunk/test/scudo/valloc.c
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/test/scudo/valloc.c?rev=334843&r1=334842&r2=334843&view=diff
==============================================================================
--- compiler-rt/trunk/test/scudo/valloc.c (original)
+++ compiler-rt/trunk/test/scudo/valloc.c Fri Jun 15 09:45:19 2018
@@ -1,6 +1,6 @@
 // RUN: %clang_scudo %s -o %t
 // RUN:                                                 %run %t valid   2>&1
-// RUN:                                             not %run %t invalid 2>&1
+// RUN:                                             not %run %t invalid 2>&1 | FileCheck %s
 // RUN: %env_scudo_opts=allocator_may_return_null=1     %run %t invalid 2>&1
 // UNSUPPORTED: android
 
@@ -54,6 +54,7 @@ int main(int argc, char **argv)
   if (!strcmp(argv[1], "invalid")) {
     // Size passed to pvalloc overflows when rounded up.
     p = pvalloc((size_t)-1);
+    // CHECK: Scudo ERROR: pvalloc parameters overflow
     assert(!p);
     assert(errno == ENOMEM);
     errno = 0;




More information about the llvm-commits mailing list