diff --git a/Zend/zend_string.h b/Zend/zend_string.h index ad66fe168c8e..675a953f2462 100644 --- a/Zend/zend_string.h +++ b/Zend/zend_string.h @@ -127,6 +127,12 @@ static zend_always_inline zend_string *ZSTR_KNOWN(size_t idx) { #define _ZSTR_STRUCT_SIZE(len) (_ZSTR_HEADER_SIZE + len + 1) +/* ALIGN(n * m + header + l + 1). The "+ ALIGNMENT - 1" of the rounding is + * done inside the overflow check, so the final "& MASK" can only shrink + * the value and can not wrap. */ +#define _ZSTR_SAFE_STRUCT_SIZE(n, m, l) \ + (zend_safe_address_guarded(n, m, _ZSTR_STRUCT_SIZE(l) + ZEND_MM_ALIGNMENT - 1) & ZEND_MM_ALIGNMENT_MASK) + #define ZSTR_MAX_OVERHEAD (ZEND_MM_ALIGNED_SIZE(_ZSTR_HEADER_SIZE + 1)) #define ZSTR_MAX_LEN (SIZE_MAX - ZSTR_MAX_OVERHEAD) @@ -198,7 +204,7 @@ static zend_always_inline zend_string *zend_string_alloc(size_t len, bool persis static zend_always_inline zend_string *zend_string_safe_alloc(size_t n, size_t m, size_t l, bool persistent) { - zend_string *ret = (zend_string *)safe_pemalloc(n, m, ZEND_MM_ALIGNED_SIZE(_ZSTR_STRUCT_SIZE(l)), persistent); + zend_string *ret = (zend_string *)pemalloc(_ZSTR_SAFE_STRUCT_SIZE(n, m, l), persistent); GC_SET_REFCOUNT(ret, 1); GC_TYPE_INFO(ret) = GC_STRING | ((persistent ? IS_STR_PERSISTENT : 0) << GC_FLAGS_SHIFT); @@ -325,7 +331,7 @@ static zend_always_inline zend_string *zend_string_safe_realloc(zend_string *s, if (!ZSTR_IS_INTERNED(s)) { if (GC_REFCOUNT(s) == 1) { - ret = (zend_string *)safe_perealloc(s, n, m, ZEND_MM_ALIGNED_SIZE(_ZSTR_STRUCT_SIZE(l)), persistent); + ret = (zend_string *)perealloc(s, _ZSTR_SAFE_STRUCT_SIZE(n, m, l), persistent); ZSTR_LEN(ret) = (n * m) + l; zend_string_forget_hash_val(ret); return ret; diff --git a/ext/standard/tests/strings/chunk_split_variation2_32bit.phpt b/ext/standard/tests/strings/chunk_split_variation2_32bit.phpt index c83a37f00edb..8f56cd96fbc3 100644 --- a/ext/standard/tests/strings/chunk_split_variation2_32bit.phpt +++ b/ext/standard/tests/strings/chunk_split_variation2_32bit.phpt @@ -16,4 +16,4 @@ var_dump(chunk_split($a,$b,$c)); --EXPECTF-- *** Testing chunk_split() : unexpected large 'end' string argument variation 2 *** -Fatal error: Possible integer overflow in memory allocation (65537 * 65537 + %r65556|65560%r) in %s on line %d +Fatal error: Possible integer overflow in memory allocation (65537 * 65537 + %r65557|65561%r) in %s on line %d