diff --git a/include/mimalloc-internal.h b/include/mimalloc-internal.h index 3a3f5c4d..88971bbb 100644 --- a/include/mimalloc-internal.h +++ b/include/mimalloc-internal.h @@ -109,6 +109,9 @@ bool _mi_page_is_valid(mi_page_t* page); #define mi_likely(x) (x) #endif +#ifndef __has_builtin +#define __has_builtin(x) 0 +#endif #if defined(_MSC_VER) #define mi_decl_noinline __declspec(noinline) @@ -146,6 +149,17 @@ static inline bool mi_mul_overflow(size_t size, size_t count, size_t* total) { && size > 0 && (SIZE_MAX / size) < count); } +// Overflow detecting addition +static inline bool mi_add_overflow(size_t a, size_t b, size_t* total) { +#if __has_builtin(__builtin_add_overflow) || __GNUC__ >= 5 + return __builtin_add_overflow(a, b, total); +#else + if (a >= (SIZE_MAX - b)) return true; // overflow + *total = a + b; + return false; +#endif +} + // Align a byte size to a size in _machine words_, // i.e. byte size == `wsize*sizeof(void*)`. static inline size_t _mi_wsize_from_size(size_t size) { diff --git a/src/alloc-posix.c b/src/alloc-posix.c index b3185f15..8758c096 100644 --- a/src/alloc-posix.c +++ b/src/alloc-posix.c @@ -65,8 +65,10 @@ void* mi_valloc(size_t size) mi_attr_noexcept { void* mi_pvalloc(size_t size) mi_attr_noexcept { size_t psize = _mi_os_page_size(); - if (size >= SIZE_MAX - psize) return NULL; // overflow - size_t asize = ((size + psize - 1) / psize) * psize; + size_t asize; + if (mi_unlikely(mi_add_overflow(size, psize, &asize))) + return NULL; // overflow + asize = ((asize - 1) / psize) * psize; // TODO: use _mi_align_down return mi_malloc_aligned(asize, psize); } diff --git a/src/os.c b/src/os.c index f9705992..0be6024c 100644 --- a/src/os.c +++ b/src/os.c @@ -302,8 +302,9 @@ static void* mi_os_mem_alloc_aligned(size_t size, size_t alignment, bool commit, // if not aligned, free it, overallocate, and unmap around it if (((uintptr_t)p % alignment != 0)) { mi_os_mem_free(p, size, stats); - if (size >= (SIZE_MAX - alignment)) return NULL; // overflow - size_t over_size = size + alignment; + size_t over_size; + if (mi_unlikely(mi_add_overflow(size, alignment, &over_size))) + return NULL; // overflow #if _WIN32 // over-allocate and than re-allocate exactly at an aligned address in there.