@@ -131,24 +131,14 @@ static zend_always_inline zend_string *ZSTR_KNOWN(size_t idx) {
131131#define ZSTR_MAX_OVERHEAD (ZEND_MM_ALIGNED_SIZE(_ZSTR_HEADER_SIZE + 1))
132132#define ZSTR_MAX_LEN (SIZE_MAX - ZSTR_MAX_OVERHEAD)
133133
134- /* Returns n * m + l, or SIZE_MAX on fallible overflow. Rejects lengths above
135- * ZSTR_MAX_LEN so the aligned allocation size of the string can not wrap. */
136- static zend_always_inline size_t zend_string_safe_len (size_t n , size_t m , size_t l , bool fallible )
137- {
138- bool overflow ;
139- size_t len = zend_safe_address (n , m , l , & overflow );
140-
141- if (UNEXPECTED (overflow || len > ZSTR_MAX_LEN )) {
142- zend_mm_delayed_error_or_panic (fallible , "Possible integer overflow in memory allocation (%zu * %zu + %zu)" , n , m , l );
143- if (!fallible ) {
144- /* zend_mm_delayed_error_or_panic() aborts for !fallible, but its body
145- * is in zend_alloc.c and is not visible when compiling other source files.
146- * Its declaration cannot use ZEND_NORETURN because the fallible path returns. */
147- ZEND_UNREACHABLE ();
148- }
149- return SIZE_MAX ;
134+ /* Offset for safe_*alloc(n, m, offset) to size the string like zend_string_alloc(n * m + l). */
135+ static zend_always_inline size_t zend_string_safe_offset (size_t n , size_t m , size_t l )
136+ {
137+ if (UNEXPECTED (l > ZSTR_MAX_LEN )) {
138+ return SIZE_MAX ; /* Rejected by the allocator. */
150139 }
151- return len ;
140+ /* Works even if n * m wraps, allocator detects that overflow. */
141+ return ZEND_MM_ALIGNED_SIZE (_ZSTR_STRUCT_SIZE (n * m + l )) - n * m ;
152142}
153143
154144#define ZSTR_ALLOCA_ALLOC (str , _len , use_heap ) do { \
@@ -229,11 +219,16 @@ static zend_always_inline zend_string *zend_string_alloc(size_t len, bool persis
229219/* Fallible variant of zend_string_safe_alloc */
230220static zend_always_inline zend_string * zend_string_safe_falloc (size_t n , size_t m , size_t l , bool persistent , bool fallible )
231221{
232- size_t len = zend_string_safe_len ( n , m , l , fallible && ! persistent );
233- if (UNEXPECTED (len == SIZE_MAX )) {
234- return NULL ;
222+ zend_string * ret = ( zend_string * ) safe_fpemalloc ( n , m , zend_string_safe_offset ( n , m , l ), persistent , fallible );
223+ if (ZEND_CONST_COND ( fallible , true) && UNEXPECTED (ret == NULL )) {
224+ return ret ;
235225 }
236- return zend_string_falloc (len , persistent , fallible );
226+
227+ GC_SET_REFCOUNT (ret , 1 );
228+ GC_TYPE_INFO (ret ) = GC_STRING | ((persistent ? IS_STR_PERSISTENT : 0 ) << GC_FLAGS_SHIFT );
229+ ZSTR_H (ret ) = 0 ;
230+ ZSTR_LEN (ret ) = (n * m ) + l ;
231+ return ret ;
237232}
238233
239234static zend_always_inline zend_string * zend_string_safe_alloc (size_t n , size_t m , size_t l , bool persistent )
@@ -406,27 +401,23 @@ static zend_always_inline zend_string *zend_string_truncate(zend_string *s, size
406401static zend_always_inline zend_string * zend_string_safe_frealloc (zend_string * s , size_t n , size_t m , size_t l , bool persistent , bool fallible )
407402{
408403 zend_string * ret ;
409- size_t len = zend_string_safe_len (n , m , l , fallible && !persistent );
410- if (UNEXPECTED (len == SIZE_MAX )) {
411- return NULL ;
412- }
413404
414405 if (!ZSTR_IS_INTERNED (s )) {
415406 if (GC_REFCOUNT (s ) == 1 ) {
416- ret = (zend_string * )fperealloc (s , ZEND_MM_ALIGNED_SIZE ( _ZSTR_STRUCT_SIZE ( len ) ), persistent , fallible );
407+ ret = (zend_string * )safe_fperealloc (s , n , m , zend_string_safe_offset ( n , m , l ), persistent , fallible );
417408 if (ZEND_CONST_COND (fallible , true) && !ret ) {
418409 return NULL ;
419410 }
420- ZSTR_LEN (ret ) = len ;
411+ ZSTR_LEN (ret ) = ( n * m ) + l ;
421412 zend_string_forget_hash_val (ret );
422413 return ret ;
423414 }
424415 }
425- ret = zend_string_falloc ( len , persistent , fallible );
416+ ret = zend_string_safe_falloc ( n , m , l , persistent , fallible );
426417 if (ZEND_CONST_COND (fallible , true) && !ret ) {
427418 return NULL ;
428419 }
429- memcpy (ZSTR_VAL (ret ), ZSTR_VAL (s ), MIN (len , ZSTR_LEN (s )) + 1 );
420+ memcpy (ZSTR_VAL (ret ), ZSTR_VAL (s ), MIN (( n * m ) + l , ZSTR_LEN (s )) + 1 );
430421 if (!ZSTR_IS_INTERNED (s )) {
431422 GC_DELREF (s );
432423 }
0 commit comments