diff --git a/include/jemalloc/internal/sc.h b/include/jemalloc/internal/sc.h index 17a8278a..7d2ff271 100644 --- a/include/jemalloc/internal/sc.h +++ b/include/jemalloc/internal/sc.h @@ -268,12 +268,17 @@ #define SC_LARGE_MINCLASS ((size_t)1ULL << (LG_PAGE + SC_LG_NGROUP)) #define SC_LG_LARGE_MINCLASS (LG_PAGE + SC_LG_NGROUP) -/* Internal; only used for the definition of SC_LARGE_MAXCLASS. */ -#define SC_MAX_BASE ((size_t)1 << (SC_PTR_BITS - 2)) -#define SC_MAX_DELTA ((size_t)1 << (SC_PTR_BITS - 2 - SC_LG_NGROUP)) - -/* The largest size class supported. */ -#define SC_LARGE_MAXCLASS (SC_MAX_BASE + (SC_NGROUP - 1) * SC_MAX_DELTA) +/* + * The largest size class supported. Spell this out directly to avoid + * expanding subtractive arithmetic at every use site. + */ +#if LG_SIZEOF_PTR == 3 +# define SC_LARGE_MAXCLASS 0x7000000000000000ULL +#elif LG_SIZEOF_PTR == 2 +# define SC_LARGE_MAXCLASS 0x70000000ULL +#else +# error "Unsupported pointer size" +#endif /* Maximum number of regions in one slab. */ #ifndef CONFIG_LG_SLAB_MAXREGS diff --git a/include/jemalloc/internal/sz.h b/include/jemalloc/internal/sz.h index d75a3034..3ee8a6b3 100644 --- a/include/jemalloc/internal/sz.h +++ b/include/jemalloc/internal/sz.h @@ -314,12 +314,20 @@ sz_size2index_usize_fastpath(size_t size, szind_t *ind, size_t *usize) { JEMALLOC_ALWAYS_INLINE size_t sz_s2u_compute_using_delta(size_t size) { + if (unlikely(size > SC_LARGE_MAXCLASS)) { + return 0; + } + size_t x = lg_floor((size << 1) - 1); size_t lg_delta = (x < SC_LG_NGROUP + LG_QUANTUM + 1) ? LG_QUANTUM : x - SC_LG_NGROUP - 1; size_t delta = ZU(1) << lg_delta; size_t delta_mask = delta - 1; + if (unlikely(size > SIZE_T_MAX - delta_mask)) { + return 0; + } + size_t usize = (size + delta_mask) & ~delta_mask; return usize; } @@ -385,7 +393,11 @@ JEMALLOC_ALWAYS_INLINE size_t sz_sa2u(size_t size, size_t alignment) { size_t usize; - assert(alignment != 0 && ((alignment - 1) & alignment) == 0); + if (unlikely(alignment == 0)) { + return 0; + } + size_t alignment_mask = alignment - 1; + assert((alignment_mask & alignment) == 0); /* Try for a small size class. */ if (size <= SC_SMALL_MAXCLASS && alignment <= PAGE) { @@ -403,7 +415,10 @@ sz_sa2u(size_t size, size_t alignment) { * 144 | 10100000 | 32 * 192 | 11000000 | 64 */ - usize = sz_s2u(ALIGNMENT_CEILING(size, alignment)); + if (unlikely(size > SIZE_T_MAX - alignment_mask)) { + return 0; + } + usize = sz_s2u((size + alignment_mask) & ~alignment_mask); if (usize < SC_LARGE_MINCLASS) { return usize; } diff --git a/test/unit/size_classes.c b/test/unit/size_classes.c index 5379047c..27f8cefd 100644 --- a/test/unit/size_classes.c +++ b/test/unit/size_classes.c @@ -190,6 +190,9 @@ TEST_BEGIN(test_overflow) { max_size_class = get_max_size_class(); max_psz = max_size_class + PAGE; + expect_zu_eq(max_size_class, SC_LARGE_MAXCLASS, + "Computed max size class should match SC_LARGE_MAXCLASS"); + expect_u_eq(sz_size2index(max_size_class + 1), SC_NSIZES, "sz_size2index() should return NSIZES on overflow"); expect_u_eq(sz_size2index(ZU(PTRDIFF_MAX) + 1), SC_NSIZES, @@ -203,6 +206,14 @@ TEST_BEGIN(test_overflow) { "sz_s2u() should return 0 for unsupported size"); expect_zu_eq( sz_s2u(SIZE_T_MAX), 0, "sz_s2u() should return 0 on overflow"); + expect_zu_eq(sz_s2u_compute_using_delta(SC_LARGE_MAXCLASS + 1), 0, + "sz_s2u_compute_using_delta() should return 0 for unsupported size"); + expect_zu_eq(sz_s2u_compute_using_delta(SIZE_T_MAX), 0, + "sz_s2u_compute_using_delta() should return 0 on overflow"); + expect_zu_eq(sz_sa2u(1, 0), 0, + "sz_sa2u() should return 0 for zero alignment"); + expect_zu_eq(sz_sa2u(SIZE_T_MAX, PAGE), 0, + "sz_sa2u() should return 0 on overflow"); expect_u_eq(sz_psz2ind(max_size_class + 1), SC_NPSIZES, "sz_psz2ind() should return NPSIZES on overflow");