@@ -127,6 +127,12 @@ static zend_always_inline zend_string *ZSTR_KNOWN(size_t idx) {
127127
128128#define _ZSTR_STRUCT_SIZE (len ) (_ZSTR_HEADER_SIZE + len + 1)
129129
130+ /* ALIGN(n * m + header + l + 1). The "+ ALIGNMENT - 1" of the rounding is
131+ * done inside the overflow check, so the final "& MASK" can only shrink
132+ * the value and can not wrap. */
133+ #define _ZSTR_SAFE_STRUCT_SIZE (n , m , l ) \
134+ (zend_safe_address_guarded(n, m, _ZSTR_STRUCT_SIZE(l) + ZEND_MM_ALIGNMENT - 1) & ZEND_MM_ALIGNMENT_MASK)
135+
130136#define ZSTR_MAX_OVERHEAD (ZEND_MM_ALIGNED_SIZE(_ZSTR_HEADER_SIZE + 1))
131137#define ZSTR_MAX_LEN (SIZE_MAX - ZSTR_MAX_OVERHEAD)
132138
@@ -198,7 +204,7 @@ static zend_always_inline zend_string *zend_string_alloc(size_t len, bool persis
198204
199205static zend_always_inline zend_string * zend_string_safe_alloc (size_t n , size_t m , size_t l , bool persistent )
200206{
201- zend_string * ret = (zend_string * )safe_pemalloc ( n , m , ZEND_MM_ALIGNED_SIZE ( _ZSTR_STRUCT_SIZE ( l ) ), persistent );
207+ zend_string * ret = (zend_string * )pemalloc ( _ZSTR_SAFE_STRUCT_SIZE ( n , m , l ), persistent );
202208
203209 GC_SET_REFCOUNT (ret , 1 );
204210 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,
325331
326332 if (!ZSTR_IS_INTERNED (s )) {
327333 if (GC_REFCOUNT (s ) == 1 ) {
328- ret = (zend_string * )safe_perealloc (s , n , m , ZEND_MM_ALIGNED_SIZE ( _ZSTR_STRUCT_SIZE ( l ) ), persistent );
334+ ret = (zend_string * )perealloc (s , _ZSTR_SAFE_STRUCT_SIZE ( n , m , l ), persistent );
329335 ZSTR_LEN (ret ) = (n * m ) + l ;
330336 zend_string_forget_hash_val (ret );
331337 return ret ;
0 commit comments