diff --git a/NEWS b/NEWS index 89bf5c1dda1..f352246fb79 100644 --- a/NEWS +++ b/NEWS @@ -2,6 +2,8 @@ PHP NEWS ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||| ?? ??? ????, PHP 8.2.8 +- Standard: + . Fix access on NULL pointer in array_merge_recursive(). (ilutov) 01 Jun 2023, PHP 8.2.7 diff --git a/Zend/tests/array_merge_recursive_next_key_overflow.phpt b/Zend/tests/array_merge_recursive_next_key_overflow.phpt new file mode 100644 index 00000000000..f7d28729578 --- /dev/null +++ b/Zend/tests/array_merge_recursive_next_key_overflow.phpt @@ -0,0 +1,25 @@ +--TEST-- +Access on NULL pointer in array_merge_recursive() +--FILE-- + [PHP_INT_MAX => null]], + ['' => [null]], + ); +} catch (Throwable $e) { + echo $e->getMessage(), "\n"; +} + +try { + array_merge_recursive( + ['foo' => [PHP_INT_MAX => null]], + ['foo' => str_repeat('a', 2)], + ); +} catch (Throwable $e) { + echo $e->getMessage(), "\n"; +} +?> +--EXPECT-- +Cannot add element to the array as the next element is already occupied +Cannot add element to the array as the next element is already occupied diff --git a/Zend/zend_execute.c b/Zend/zend_execute.c index 6aca553c626..89610f84b5e 100644 --- a/Zend/zend_execute.c +++ b/Zend/zend_execute.c @@ -2194,7 +2194,7 @@ static zend_never_inline ZEND_COLD void ZEND_FASTCALL zend_use_scalar_as_array(v zend_throw_error(NULL, "Cannot use a scalar value as an array"); } -static zend_never_inline ZEND_COLD void ZEND_FASTCALL zend_cannot_add_element(void) +ZEND_API zend_never_inline ZEND_COLD void ZEND_FASTCALL zend_cannot_add_element(void) { zend_throw_error(NULL, "Cannot add element to the array as the next element is already occupied"); } diff --git a/Zend/zend_execute.h b/Zend/zend_execute.h index 70449f5bf62..2a61f4bff71 100644 --- a/Zend/zend_execute.h +++ b/Zend/zend_execute.h @@ -76,6 +76,8 @@ ZEND_API ZEND_COLD void zend_wrong_string_offset_error(void); ZEND_API ZEND_COLD void ZEND_FASTCALL zend_readonly_property_modification_error(zend_property_info *info); ZEND_API ZEND_COLD void ZEND_FASTCALL zend_readonly_property_indirect_modification_error(zend_property_info *info); +ZEND_API ZEND_COLD void ZEND_FASTCALL zend_cannot_add_element(void); + ZEND_API bool zend_verify_scalar_type_hint(uint32_t type_mask, zval *arg, bool strict, bool is_internal_arg); ZEND_API ZEND_COLD void zend_verify_arg_error( const zend_function *zf, const zend_arg_info *arg_info, uint32_t arg_num, zval *value); diff --git a/ext/standard/array.c b/ext/standard/array.c index 8a74704967f..8a327378b8c 100644 --- a/ext/standard/array.c +++ b/ext/standard/array.c @@ -3728,7 +3728,12 @@ PHPAPI int php_array_merge_recursive(HashTable *dest, HashTable *src) /* {{{ */ } } else { Z_TRY_ADDREF_P(src_zval); - zend_hash_next_index_insert(Z_ARRVAL_P(dest_zval), src_zval); + zval *zv = zend_hash_next_index_insert(Z_ARRVAL_P(dest_zval), src_zval); + if (EXPECTED(!zv)) { + Z_TRY_DELREF_P(src_zval); + zend_cannot_add_element(); + return 0; + } } zval_ptr_dtor(&tmp); } else { @@ -3737,6 +3742,10 @@ PHPAPI int php_array_merge_recursive(HashTable *dest, HashTable *src) /* {{{ */ } } else { zval *zv = zend_hash_next_index_insert(dest, src_entry); + if (UNEXPECTED(!zv)) { + zend_cannot_add_element(); + return 0; + } zval_add_ref(zv); } } ZEND_HASH_FOREACH_END();