[php-src] PHP-8.5: Merge branch 'PHP-8.4' into PHP-8.5

From: Date: Sat, 10 Oct 2026 09:20:30 +0000
Subject: [php-src] PHP-8.5: Merge branch 'PHP-8.4' into PHP-8.5
Groups: php.cvs 
Request: Send a blank email to php-cvs+get-142149@lists.php.net to get a copy of this message
Author: ndossche (ndossche) Date: 2026-10-10T11:19:34+02:00 Commit: https://github.com/php/php-src/commit/2cc3aa8af7b31bd346e5cf2f6b760c5848d70d3b Raw diff: https://github.com/php/php-src/commit/2cc3aa8af7b31bd346e5cf2f6b760c5848d70d3b.diff Merge branch 'PHP-8.4' into PHP-8.5 * PHP-8.4: Fix throwing behaviour with recursive arrays in VM Changed paths: A ext/opcache/tests/is_identical_nothrow_recursive_array.phpt M NEWS M Zend/zend_vm_def.h M Zend/zend_vm_execute.h Diff: diff --git a/NEWS b/NEWS index 54b04dc734b5..34f540d39b49 100644 --- a/NEWS +++ b/NEWS @@ -17,6 +17,7 @@ PHP NEWS frame under ZEND_VM_KIND_TAILCALL). (devnexen) . Fixed bug GH-24218 (Invalid opcode for count() of a literal array without SCCP). (lazerg) + . Fix throwing behaviour with recursive arrays in VM. (ndossche) - FPM: . Fixed bug GH-24229 (fcgi_close() passes shutdown() a literal 1, which is diff --git a/Zend/zend_vm_def.h b/Zend/zend_vm_def.h index f107f722526e..21074bc688d9 100644 --- a/Zend/zend_vm_def.h +++ b/Zend/zend_vm_def.h @@ -10135,11 +10135,11 @@ ZEND_VM_TYPE_SPEC_HANDLER(ZEND_IS_NOT_IDENTICAL, op->op2_type == IS_CONST && (Z_ ZEND_VM_SMART_BRANCH(result, 0); } -ZEND_VM_TYPE_SPEC_HANDLER(ZEND_IS_IDENTICAL, op->op1_type == IS_CV && (op->op2_type & (IS_CONST|IS_CV)) && !(op1_info & (MAY_BE_UNDEF|MAY_BE_REF)) && !(op2_info & (MAY_BE_UNDEF|MAY_BE_REF)), ZEND_IS_IDENTICAL_NOTHROW, CV, CONST|CV, SPEC(COMMUTATIVE)) +ZEND_VM_TYPE_SPEC_HANDLER(ZEND_IS_IDENTICAL, op->op1_type == IS_CV && (op->op2_type & (IS_CONST|IS_CV)) && !(op1_info & (MAY_BE_UNDEF|MAY_BE_REF)) && !(op2_info & (MAY_BE_UNDEF|MAY_BE_REF)) && !((op1_info & op2_info) & MAY_BE_ARRAY_OF_ARRAY), ZEND_IS_IDENTICAL_NOTHROW, CV, CONST|CV, SPEC(COMMUTATIVE)) { /* This is declared below the specializations for MAY_BE_LONG/MAY_BE_DOUBLE so those will be used instead if possible. */ /* This optimizes $x === SOME_CONST_EXPR and $x === $y for non-refs and non-undef, which can't throw. */ - /* (Infinite recursion when comparing arrays is an uncatchable fatal error) */ + /* Comparing two arrays that may contain arrays is excluded, as recursion throws an Error. */ USE_OPLINE zval *op1, *op2; bool result; @@ -10151,7 +10151,7 @@ ZEND_VM_TYPE_SPEC_HANDLER(ZEND_IS_IDENTICAL, op->op1_type == IS_CV && (op->op2_t ZEND_VM_SMART_BRANCH(result, 0); } -ZEND_VM_TYPE_SPEC_HANDLER(ZEND_IS_NOT_IDENTICAL, op->op1_type == IS_CV && (op->op2_type & (IS_CONST|IS_CV)) && !(op1_info & (MAY_BE_UNDEF|MAY_BE_REF)) && !(op2_info & (MAY_BE_UNDEF|MAY_BE_REF)), ZEND_IS_NOT_IDENTICAL_NOTHROW, CV, CONST|CV, SPEC(COMMUTATIVE)) +ZEND_VM_TYPE_SPEC_HANDLER(ZEND_IS_NOT_IDENTICAL, op->op1_type == IS_CV && (op->op2_type & (IS_CONST|IS_CV)) && !(op1_info & (MAY_BE_UNDEF|MAY_BE_REF)) && !(op2_info & (MAY_BE_UNDEF|MAY_BE_REF)) && !((op1_info & op2_info) & MAY_BE_ARRAY_OF_ARRAY), ZEND_IS_NOT_IDENTICAL_NOTHROW, CV, CONST|CV, SPEC(COMMUTATIVE)) { USE_OPLINE zval *op1, *op2; diff --git a/Zend/zend_vm_execute.h b/Zend/zend_vm_execute.h index f0b244f53c33..2b5d042666c4 100644 --- a/Zend/zend_vm_execute.h +++ b/Zend/zend_vm_execute.h @@ -47060,7 +47060,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_OPCODE_HANDLER_FUNC_CCONV ZEND_IS_IDENTICAL_ { /* This is declared below the specializations for MAY_BE_LONG/MAY_BE_DOUBLE so those will be used instead if possible. */ /* This optimizes $x === SOME_CONST_EXPR and $x === $y for non-refs and non-undef, which can't throw. */ - /* (Infinite recursion when comparing arrays is an uncatchable fatal error) */ + /* Comparing two arrays that may contain arrays is excluded, as recursion throws an Error. */ USE_OPLINE zval *op1, *op2; bool result; @@ -56505,7 +56505,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_OPCODE_HANDLER_FUNC_CCONV ZEND_IS_IDENTICAL_ { /* This is declared below the specializations for MAY_BE_LONG/MAY_BE_DOUBLE so those will be used instead if possible. */ /* This optimizes $x === SOME_CONST_EXPR and $x === $y for non-refs and non-undef, which can't throw. */ - /* (Infinite recursion when comparing arrays is an uncatchable fatal error) */ + /* Comparing two arrays that may contain arrays is excluded, as recursion throws an Error. */ USE_OPLINE zval *op1, *op2; bool result; @@ -102570,7 +102570,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_OPCODE_HANDLER_CCONV ZEND_IS_IDENTICAL_NOTHR { /* This is declared below the specializations for MAY_BE_LONG/MAY_BE_DOUBLE so those will be used instead if possible. */ /* This optimizes $x === SOME_CONST_EXPR and $x === $y for non-refs and non-undef, which can't throw. */ - /* (Infinite recursion when comparing arrays is an uncatchable fatal error) */ + /* Comparing two arrays that may contain arrays is excluded, as recursion throws an Error. */ USE_OPLINE zval *op1, *op2; bool result; @@ -111913,7 +111913,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_OPCODE_HANDLER_CCONV ZEND_IS_IDENTICAL_NOTHR { /* This is declared below the specializations for MAY_BE_LONG/MAY_BE_DOUBLE so those will be used instead if possible. */ /* This optimizes $x === SOME_CONST_EXPR and $x === $y for non-refs and non-undef, which can't throw. */ - /* (Infinite recursion when comparing arrays is an uncatchable fatal error) */ + /* Comparing two arrays that may contain arrays is excluded, as recursion throws an Error. */ USE_OPLINE zval *op1, *op2; bool result; @@ -129540,7 +129540,7 @@ ZEND_API void ZEND_FASTCALL zend_vm_set_opcode_handler_ex(zend_op* op, uint32_t break; } spec = 3111 | SPEC_RULE_SMART_BRANCH | SPEC_RULE_COMMUTATIVE; - } else if (op->op1_type == IS_CV && (op->op2_type & (IS_CONST|IS_CV)) && !(op1_info & (MAY_BE_UNDEF|MAY_BE_REF)) && !(op2_info & (MAY_BE_UNDEF|MAY_BE_REF))) { + } else if (op->op1_type == IS_CV && (op->op2_type & (IS_CONST|IS_CV)) && !(op1_info & (MAY_BE_UNDEF|MAY_BE_REF)) && !(op2_info & (MAY_BE_UNDEF|MAY_BE_REF)) && !((op1_info & op2_info) & MAY_BE_ARRAY_OF_ARRAY)) { spec = 3117 | SPEC_RULE_OP2 | SPEC_RULE_COMMUTATIVE; } break; @@ -129563,7 +129563,7 @@ ZEND_API void ZEND_FASTCALL zend_vm_set_opcode_handler_ex(zend_op* op, uint32_t break; } spec = 3114 | SPEC_RULE_SMART_BRANCH | SPEC_RULE_COMMUTATIVE; - } else if (op->op1_type == IS_CV && (op->op2_type & (IS_CONST|IS_CV)) && !(op1_info & (MAY_BE_UNDEF|MAY_BE_REF)) && !(op2_info & (MAY_BE_UNDEF|MAY_BE_REF))) { + } else if (op->op1_type == IS_CV && (op->op2_type & (IS_CONST|IS_CV)) && !(op1_info & (MAY_BE_UNDEF|MAY_BE_REF)) && !(op2_info & (MAY_BE_UNDEF|MAY_BE_REF)) && !((op1_info & op2_info) & MAY_BE_ARRAY_OF_ARRAY)) { spec = 3122 | SPEC_RULE_OP2 | SPEC_RULE_COMMUTATIVE; } break; diff --git a/ext/opcache/tests/is_identical_nothrow_recursive_array.phpt b/ext/opcache/tests/is_identical_nothrow_recursive_array.phpt new file mode 100644 index 000000000000..a9dcd5b057a9 --- /dev/null +++ b/ext/opcache/tests/is_identical_nothrow_recursive_array.phpt @@ -0,0 +1,39 @@ +--TEST-- +IS_IDENTICAL/IS_NOT_IDENTICAL must not use the NOTHROW handler for arrays that may contain arrays +--INI-- +opcache.enable=1 +opcache.enable_cli=1 +opcache.optimization_level=-1 +--EXTENSIONS-- +opcache +--FILE-- +<?php +function identical(array $a, array $b) { + $r = $a === $b; + echo "not reached\n"; + return $r; +} + +function not_identical(array $a, array $b) { + $r = $a !== $b; + echo "not reached\n"; + return $r; +} + +$x = [&$x]; + +try { + identical($x, [[]]); +} catch (Throwable $e) { + echo $e::class, ": ", $e->getMessage(), " on line ", $e->getLine(), "\n"; +} + +try { + not_identical($x, [[]]); +} catch (Throwable $e) { + echo $e::class, ": ", $e->getMessage(), " on line ", $e->getLine(), "\n"; +} +?> +--EXPECT-- +Error: Nesting level too deep - recursive dependency? on line 3 +Error: Nesting level too deep - recursive dependency? on line 9

« previous php.cvs (#142149) next »