Index: lib/sanitizer_common/sanitizer_allocator_checks.h =================================================================== --- lib/sanitizer_common/sanitizer_allocator_checks.h +++ lib/sanitizer_common/sanitizer_allocator_checks.h @@ -59,6 +59,12 @@ return (max / size) < n; } +// Returns true if the size passed to pvalloc overflows when rounded to the next +// multiple of page_size. +INLINE bool CheckForPvallocOverflow(uptr size, uptr page_size) { + return RoundUpTo(size, page_size) < size; +} + } // namespace __sanitizer #endif // SANITIZER_ALLOCATOR_CHECKS_H Index: lib/scudo/scudo_allocator.cpp =================================================================== --- lib/scudo/scudo_allocator.cpp +++ lib/scudo/scudo_allocator.cpp @@ -665,6 +665,10 @@ void *scudoPvalloc(uptr Size) { uptr PageSize = GetPageSizeCached(); + if (UNLIKELY(CheckForPvallocOverflow(Size, PageSize))) { + errno = errno_ENOMEM; + return ScudoAllocator::FailureHandler::OnBadRequest(); + } // pvalloc(0) should allocate one page. Size = Size ? RoundUpTo(Size, PageSize) : PageSize; return SetErrnoOnNull(Instance.allocate(Size, PageSize, FromMemalign)); Index: test/scudo/memalign.cpp =================================================================== --- test/scudo/memalign.cpp +++ test/scudo/memalign.cpp @@ -8,14 +8,10 @@ #include #include #include +#include #include #include - -// Reduce the size of the quarantine, or the test can run out of aligned memory -// on 32-bit for the larger alignments. -extern "C" const char *__scudo_default_options() { - return "QuarantineSizeMb=1"; -} +#include // Sometimes the headers may not have this... extern "C" void *aligned_alloc (size_t alignment, size_t size); @@ -26,15 +22,30 @@ size_t alignment = 1U << 12; size_t size = 1U << 12; int err; + size_t page_size; assert(argc == 2); + page_size = sysconf(_SC_PAGESIZE); + // Checks that the page size is a power of two. + assert((page_size & (page_size - 1)) == 0); + if (!strcmp(argv[1], "valid")) { posix_memalign(&p, alignment, size); assert(p); + assert(((uintptr_t)p & (alignment - 1)) == 0); free(p); p = aligned_alloc(alignment, size); assert(p); + assert(((uintptr_t)p & (alignment - 1)) == 0); + free(p); + p = pvalloc(1); + assert(p); + assert(((uintptr_t)p & (page_size - 1)) == 0); + free(p); + p = pvalloc(size); + assert(p); + assert(((uintptr_t)p & (page_size - 1)) == 0); free(p); // Tests various combinations of alignment and sizes for (int i = (sizeof(void *) == 4) ? 3 : 4; i < 19; i++) { @@ -44,6 +55,7 @@ for (int k = 0; k < 3; k++) { p = memalign(alignment, size - (2 * sizeof(void *) * k)); assert(p); + assert(((uintptr_t)p & (alignment - 1)) == 0); free(p); } } @@ -54,6 +66,7 @@ for (int k = 0; k < 3; k++) { p = memalign(alignment, 0x1000 - (2 * sizeof(void *) * k)); assert(p); + assert(((uintptr_t)p & (alignment - 1)) == 0); free(p); } } @@ -75,6 +88,15 @@ err = posix_memalign(&p, 2, size); assert(p == p_unchanged); assert(err == EINVAL); + errno = 0; + // Size passed to pvalloc overflows when rounded up. + p = pvalloc((size_t)-1); + assert(!p); + assert(errno == ENOMEM); + errno = 0; + p = pvalloc((size_t)-page_size); + assert(!p); + assert(errno == ENOMEM); } return 0; }