diff --git a/compiler-rt/lib/scudo/scudo_allocator.cpp b/compiler-rt/lib/scudo/scudo_allocator.cpp index 1d0db84a5aaf..a2a3c8ba3395 100644 --- a/compiler-rt/lib/scudo/scudo_allocator.cpp +++ b/compiler-rt/lib/scudo/scudo_allocator.cpp @@ -22,8 +22,7 @@ #include "sanitizer_common/sanitizer_allocator_interface.h" #include "sanitizer_common/sanitizer_quarantine.h" -#include -#include +#include #include namespace __scudo { @@ -341,7 +340,7 @@ struct ScudoAllocator { // Helper function that checks for a valid Scudo chunk. nullptr isn't. bool isValidPointer(const void *UserPtr) { initThreadMaybe(); - if (!UserPtr) + if (UNLIKELY(!UserPtr)) return false; uptr UserBeg = reinterpret_cast(UserPtr); if (!IsAligned(UserBeg, MinAlignment)) @@ -353,22 +352,19 @@ struct ScudoAllocator { void *allocate(uptr Size, uptr Alignment, AllocType Type, bool ForceZeroContents = false) { initThreadMaybe(); - if (UNLIKELY(!IsPowerOfTwo(Alignment))) { - dieWithMessage("ERROR: alignment is not a power of 2\n"); - } - if (Alignment > MaxAlignment) + if (UNLIKELY(Alignment > MaxAlignment)) return FailureHandler::OnBadRequest(); - if (Alignment < MinAlignment) + if (UNLIKELY(Alignment < MinAlignment)) Alignment = MinAlignment; - if (Size >= MaxAllowedMallocSize) + if (UNLIKELY(Size >= MaxAllowedMallocSize)) return FailureHandler::OnBadRequest(); - if (Size == 0) + if (UNLIKELY(Size == 0)) Size = 1; uptr NeededSize = RoundUpTo(Size, MinAlignment) + AlignedChunkHeaderSize; uptr AlignedSize = (Alignment > MinAlignment) ? NeededSize + (Alignment - AlignedChunkHeaderSize) : NeededSize; - if (AlignedSize >= MaxAllowedMallocSize) + if (UNLIKELY(AlignedSize >= MaxAllowedMallocSize)) return FailureHandler::OnBadRequest(); // Primary and Secondary backed allocations have a different treatment. We @@ -393,7 +389,7 @@ struct ScudoAllocator { Ptr = BackendAllocator.Allocate(&FallbackAllocatorCache, AllocationSize, AllocationAlignment, FromPrimary); } - if (!Ptr) + if (UNLIKELY(!Ptr)) return FailureHandler::OnOOM(); // If requested, we will zero out the entire contents of the returned chunk. @@ -404,7 +400,7 @@ struct ScudoAllocator { UnpackedHeader Header = {}; uptr AllocBeg = reinterpret_cast(Ptr); uptr UserBeg = AllocBeg + AlignedChunkHeaderSize; - if (!IsAligned(UserBeg, Alignment)) { + if (UNLIKELY(!IsAligned(UserBeg, Alignment))) { // Since the Secondary takes care of alignment, a non-aligned pointer // means it is from the Primary. It is also the only case where the offset // field of the header would be non-zero. @@ -481,7 +477,7 @@ struct ScudoAllocator { void deallocate(void *UserPtr, uptr DeleteSize, AllocType Type) { initThreadMaybe(); // if (&__sanitizer_free_hook) __sanitizer_free_hook(UserPtr); - if (!UserPtr) + if (UNLIKELY(!UserPtr)) return; uptr UserBeg = reinterpret_cast(UserPtr); if (UNLIKELY(!IsAligned(UserBeg, MinAlignment))) { @@ -568,7 +564,7 @@ struct ScudoAllocator { // Helper function that returns the actual usable size of a chunk. uptr getUsableSize(const void *Ptr) { initThreadMaybe(); - if (!Ptr) + if (UNLIKELY(!Ptr)) return 0; uptr UserBeg = reinterpret_cast(Ptr); ScudoChunk *Chunk = getScudoChunk(UserBeg); @@ -584,10 +580,10 @@ struct ScudoAllocator { void *calloc(uptr NMemB, uptr Size) { initThreadMaybe(); - uptr Total = NMemB * Size; - if (Size != 0 && Total / Size != NMemB) // Overflow check + // TODO(kostyak): switch to CheckForCallocOverflow once D34799 lands. + if (CallocShouldReturnNullDueToOverflow(NMemB, Size)) return FailureHandler::OnBadRequest(); - return allocate(Total, MinAlignment, FromMalloc, true); + return allocate(NMemB * Size, MinAlignment, FromMalloc, true); } void commitBack(ScudoThreadContext *ThreadContext) { @@ -655,10 +651,6 @@ void *scudoValloc(uptr Size) { return Instance.allocate(Size, GetPageSizeCached(), FromMemalign); } -void *scudoMemalign(uptr Alignment, uptr Size) { - return Instance.allocate(Size, Alignment, FromMemalign); -} - void *scudoPvalloc(uptr Size) { uptr PageSize = GetPageSizeCached(); Size = RoundUpTo(Size, PageSize); @@ -669,16 +661,27 @@ void *scudoPvalloc(uptr Size) { return Instance.allocate(Size, PageSize, FromMemalign); } +void *scudoMemalign(uptr Alignment, uptr Size) { + if (UNLIKELY(!IsPowerOfTwo(Alignment))) + return ScudoAllocator::FailureHandler::OnBadRequest(); + return Instance.allocate(Size, Alignment, FromMemalign); +} + int scudoPosixMemalign(void **MemPtr, uptr Alignment, uptr Size) { + if (UNLIKELY(!IsPowerOfTwo(Alignment) || (Alignment % sizeof(void *)) != 0)) { + *MemPtr = ScudoAllocator::FailureHandler::OnBadRequest(); + return EINVAL; + } *MemPtr = Instance.allocate(Size, Alignment, FromMemalign); + if (!*MemPtr) + return ENOMEM; return 0; } void *scudoAlignedAlloc(uptr Alignment, uptr Size) { - // size must be a multiple of the alignment. To avoid a division, we first - // make sure that alignment is a power of 2. - CHECK(IsPowerOfTwo(Alignment)); - CHECK_EQ((Size & (Alignment - 1)), 0); + // Alignment must be a power of 2, Size must be a multiple of Alignment. + if (UNLIKELY(!IsPowerOfTwo(Alignment) || (Size & (Alignment - 1)) != 0)) + return ScudoAllocator::FailureHandler::OnBadRequest(); return Instance.allocate(Size, Alignment, FromMalloc); } diff --git a/compiler-rt/lib/scudo/scudo_allocator.h b/compiler-rt/lib/scudo/scudo_allocator.h index 523808750eec..29d85995a3ee 100644 --- a/compiler-rt/lib/scudo/scudo_allocator.h +++ b/compiler-rt/lib/scudo/scudo_allocator.h @@ -116,6 +116,11 @@ struct AP32 { typedef SizeClassAllocator32 PrimaryAllocator; #endif // SANITIZER_CAN_USE_ALLOCATOR64 +// __sanitizer::RoundUp has a CHECK that is extraneous for us. Use our own. +INLINE uptr RoundUpTo(uptr Size, uptr Boundary) { + return (Size + Boundary - 1) & ~(Boundary - 1); +} + #include "scudo_allocator_secondary.h" #include "scudo_allocator_combined.h" diff --git a/compiler-rt/lib/scudo/scudo_allocator_combined.h b/compiler-rt/lib/scudo/scudo_allocator_combined.h index 21c45897b94e..818272868880 100644 --- a/compiler-rt/lib/scudo/scudo_allocator_combined.h +++ b/compiler-rt/lib/scudo/scudo_allocator_combined.h @@ -45,7 +45,7 @@ class ScudoCombinedAllocator { uptr GetActuallyAllocatedSize(void *Ptr, bool FromPrimary) { if (FromPrimary) - return Primary.GetActuallyAllocatedSize(Ptr); + return PrimaryAllocator::ClassIdToSize(Primary.GetSizeClass(Ptr)); return Secondary.GetActuallyAllocatedSize(Ptr); } diff --git a/compiler-rt/lib/scudo/scudo_tls_android.cpp b/compiler-rt/lib/scudo/scudo_tls_android.cpp index 0e3602b2faf0..ec74e37c8dbc 100644 --- a/compiler-rt/lib/scudo/scudo_tls_android.cpp +++ b/compiler-rt/lib/scudo/scudo_tls_android.cpp @@ -45,7 +45,7 @@ static void initOnce() { NumberOfContexts = getNumberOfCPUs(); ThreadContexts = reinterpret_cast( MmapOrDie(sizeof(ScudoThreadContext) * NumberOfContexts, __func__)); - for (int i = 0; i < NumberOfContexts; i++) + for (uptr i = 0; i < NumberOfContexts; i++) ThreadContexts[i].init(); } diff --git a/compiler-rt/test/scudo/memalign.cpp b/compiler-rt/test/scudo/memalign.cpp index c263da75e616..856128f2489f 100644 --- a/compiler-rt/test/scudo/memalign.cpp +++ b/compiler-rt/test/scudo/memalign.cpp @@ -1,11 +1,12 @@ // RUN: %clang_scudo %s -o %t -// RUN: %run %t valid 2>&1 -// RUN: not %run %t invalid 2>&1 | FileCheck %s +// RUN: %run %t valid 2>&1 +// RUN: %run %t invalid 2>&1 // Tests that the various aligned allocation functions work as intended. Also // tests for the condition where the alignment is not a power of 2. #include +#include #include #include #include @@ -24,6 +25,7 @@ int main(int argc, char **argv) void *p = nullptr; size_t alignment = 1U << 12; size_t size = 1U << 12; + int err; assert(argc == 2); @@ -57,10 +59,22 @@ int main(int argc, char **argv) } } if (!strcmp(argv[1], "invalid")) { + // Alignment is not a power of 2. p = memalign(alignment - 1, size); - free(p); + assert(!p); + // Size is not a multiple of alignment. + p = aligned_alloc(alignment, size >> 1); + assert(!p); + p = (void *)0x42UL; + // Alignment is not a power of 2. + err = posix_memalign(&p, 3, size); + assert(!p); + assert(err == EINVAL); + p = (void *)0x42UL; + // Alignment is a power of 2, but not a multiple of size(void *). + err = posix_memalign(&p, 2, size); + assert(!p); + assert(err == EINVAL); } return 0; } - -// CHECK: ERROR: alignment is not a power of 2