diff options
author | Kostya Kortchinsky <kostyak@google.com> | 2018-06-15 16:45:19 +0000 |
---|---|---|
committer | Kostya Kortchinsky <kostyak@google.com> | 2018-06-15 16:45:19 +0000 |
commit | 4adf24502ec8c993e3da2fe0ad2f4921e5a76bb9 (patch) | |
tree | d67950f68ed4bb6455dcaf9a9041a235d274fadd /compiler-rt/lib/scudo | |
parent | a6edca72ba6962455ab427759b9380555db0d211 (diff) | |
download | bcm5719-llvm-4adf24502ec8c993e3da2fe0ad2f4921e5a76bb9.tar.gz bcm5719-llvm-4adf24502ec8c993e3da2fe0ad2f4921e5a76bb9.zip |
[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
llvm-svn: 334843
Diffstat (limited to 'compiler-rt/lib/scudo')
-rw-r--r-- | compiler-rt/lib/scudo/CMakeLists.txt | 1 | ||||
-rw-r--r-- | compiler-rt/lib/scudo/scudo_allocator.cpp | 65 | ||||
-rw-r--r-- | compiler-rt/lib/scudo/scudo_allocator_secondary.h | 2 | ||||
-rw-r--r-- | compiler-rt/lib/scudo/scudo_errors.cpp | 77 | ||||
-rw-r--r-- | compiler-rt/lib/scudo/scudo_errors.h | 35 | ||||
-rw-r--r-- | compiler-rt/lib/scudo/scudo_new_delete.cpp | 3 |
6 files changed, 158 insertions, 25 deletions
diff --git a/compiler-rt/lib/scudo/CMakeLists.txt b/compiler-rt/lib/scudo/CMakeLists.txt index 3adfe688260..32472af5c8a 100644 --- a/compiler-rt/lib/scudo/CMakeLists.txt +++ b/compiler-rt/lib/scudo/CMakeLists.txt @@ -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 diff --git a/compiler-rt/lib/scudo/scudo_allocator.cpp b/compiler-rt/lib/scudo/scudo_allocator.cpp index fba4b5ac07d..0033328a602 100644 --- a/compiler-rt/lib/scudo/scudo_allocator.cpp +++ b/compiler-rt/lib/scudo/scudo_allocator.cpp @@ -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, uptr Alignment, uptr Size) { 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)); } diff --git a/compiler-rt/lib/scudo/scudo_allocator_secondary.h b/compiler-rt/lib/scudo/scudo_allocator_secondary.h index 27eb444c5f4..425ef4d26cb 100644 --- a/compiler-rt/lib/scudo/scudo_allocator_secondary.h +++ b/compiler-rt/lib/scudo/scudo_allocator_secondary.h @@ -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; diff --git a/compiler-rt/lib/scudo/scudo_errors.cpp b/compiler-rt/lib/scudo/scudo_errors.cpp new file mode 100644 index 00000000000..d11e03cf916 --- /dev/null +++ b/compiler-rt/lib/scudo/scudo_errors.cpp @@ -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 diff --git a/compiler-rt/lib/scudo/scudo_errors.h b/compiler-rt/lib/scudo/scudo_errors.h new file mode 100644 index 00000000000..8b1af996be0 --- /dev/null +++ b/compiler-rt/lib/scudo/scudo_errors.h @@ -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_ diff --git a/compiler-rt/lib/scudo/scudo_new_delete.cpp b/compiler-rt/lib/scudo/scudo_new_delete.cpp index 948d07a5210..daa3b47dc72 100644 --- a/compiler-rt/lib/scudo/scudo_new_delete.cpp +++ b/compiler-rt/lib/scudo/scudo_new_delete.cpp @@ -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) |