Merge branch 'PHP-8.4'

* PHP-8.4:
  Fix OSS-Fuzz #418106144
  Fix OSS-Fuzz #417078295
  fix: dangling opline in ZEND_INIT_ARRAY (#18578)
This commit is contained in:
Niels Dossche 2025-05-19 19:08:29 +02:00
commit 0b48e2a267
No known key found for this signature in database
GPG key ID: B8A8AD166DF0E2E5
5 changed files with 64 additions and 3 deletions

View file

@ -0,0 +1,20 @@
--TEST--
OSS-Fuzz #418106144
--FILE--
<?php
class Foo {
function __toString(){}
}
function test($y=new Foo>''){
var_dump();
}
try {
test();
} catch (TypeError $e) {
echo $e->getMessage(), "\n";
}
?>
--EXPECT--
Foo::__toString(): Return value must be of type string, none returned

View file

@ -0,0 +1,17 @@
--TEST--
OSS-Fuzz #417078295
--FILE--
<?php
function foo() {
$a = new stdClass();
static $a = $a;
debug_zval_dump($a);
}
foo();
?>
--EXPECT--
object(stdClass)#1 (0) refcount(2){
}

View file

@ -626,9 +626,10 @@ ZEND_API zend_result ZEND_FASTCALL zend_ast_evaluate_inner(
/* op1 > op2 is the same as op2 < op1 */ /* op1 > op2 is the same as op2 < op1 */
binary_op_type op = ast->kind == ZEND_AST_GREATER binary_op_type op = ast->kind == ZEND_AST_GREATER
? is_smaller_function : is_smaller_or_equal_function; ? is_smaller_function : is_smaller_or_equal_function;
ret = op(result, &op2, &op1); op(result, &op2, &op1);
zval_ptr_dtor_nogc(&op1); zval_ptr_dtor_nogc(&op1);
zval_ptr_dtor_nogc(&op2); zval_ptr_dtor_nogc(&op2);
ret = EG(exception) ? FAILURE : SUCCESS;
} }
break; break;
case ZEND_AST_UNARY_OP: case ZEND_AST_UNARY_OP:

View file

@ -6438,6 +6438,7 @@ ZEND_VM_HANDLER(71, ZEND_INIT_ARRAY, CONST|TMP|VAR|CV|UNUSED, CONST|TMPVAR|UNUSE
uint32_t size; uint32_t size;
USE_OPLINE USE_OPLINE
SAVE_OPLINE();
array = EX_VAR(opline->result.var); array = EX_VAR(opline->result.var);
if (OP1_TYPE != IS_UNUSED) { if (OP1_TYPE != IS_UNUSED) {
size = opline->extended_value >> ZEND_ARRAY_SIZE_SHIFT; size = opline->extended_value >> ZEND_ARRAY_SIZE_SHIFT;
@ -9111,7 +9112,6 @@ ZEND_VM_HANDLER(183, ZEND_BIND_STATIC, CV, ANY, REF)
value = (zval*)((char*)ht->arData + (opline->extended_value & ~(ZEND_BIND_REF|ZEND_BIND_IMPLICIT|ZEND_BIND_EXPLICIT))); value = (zval*)((char*)ht->arData + (opline->extended_value & ~(ZEND_BIND_REF|ZEND_BIND_IMPLICIT|ZEND_BIND_EXPLICIT)));
if (opline->extended_value & ZEND_BIND_REF) { if (opline->extended_value & ZEND_BIND_REF) {
i_zval_ptr_dtor(variable_ptr);
if (UNEXPECTED(!Z_ISREF_P(value))) { if (UNEXPECTED(!Z_ISREF_P(value))) {
zend_reference *ref = (zend_reference*)emalloc(sizeof(zend_reference)); zend_reference *ref = (zend_reference*)emalloc(sizeof(zend_reference));
GC_SET_REFCOUNT(ref, 2); GC_SET_REFCOUNT(ref, 2);
@ -9126,9 +9126,11 @@ ZEND_VM_HANDLER(183, ZEND_BIND_STATIC, CV, ANY, REF)
ref->sources.ptr = NULL; ref->sources.ptr = NULL;
Z_REF_P(value) = ref; Z_REF_P(value) = ref;
Z_TYPE_INFO_P(value) = IS_REFERENCE_EX; Z_TYPE_INFO_P(value) = IS_REFERENCE_EX;
i_zval_ptr_dtor(variable_ptr);
ZVAL_REF(variable_ptr, ref); ZVAL_REF(variable_ptr, ref);
} else { } else {
Z_ADDREF_P(value); Z_ADDREF_P(value);
i_zval_ptr_dtor(variable_ptr);
ZVAL_REF(variable_ptr, Z_REF_P(value)); ZVAL_REF(variable_ptr, Z_REF_P(value));
if (OP2_TYPE != IS_UNUSED) { if (OP2_TYPE != IS_UNUSED) {
FREE_OP2(); FREE_OP2();

23
Zend/zend_vm_execute.h generated
View file

@ -7815,6 +7815,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_INIT_ARRAY_SPEC_CONST_CONST_HA
uint32_t size; uint32_t size;
USE_OPLINE USE_OPLINE
SAVE_OPLINE();
array = EX_VAR(opline->result.var); array = EX_VAR(opline->result.var);
if (IS_CONST != IS_UNUSED) { if (IS_CONST != IS_UNUSED) {
size = opline->extended_value >> ZEND_ARRAY_SIZE_SHIFT; size = opline->extended_value >> ZEND_ARRAY_SIZE_SHIFT;
@ -10244,6 +10245,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_INIT_ARRAY_SPEC_CONST_TMPVAR_H
uint32_t size; uint32_t size;
USE_OPLINE USE_OPLINE
SAVE_OPLINE();
array = EX_VAR(opline->result.var); array = EX_VAR(opline->result.var);
if (IS_CONST != IS_UNUSED) { if (IS_CONST != IS_UNUSED) {
size = opline->extended_value >> ZEND_ARRAY_SIZE_SHIFT; size = opline->extended_value >> ZEND_ARRAY_SIZE_SHIFT;
@ -11168,6 +11170,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_INIT_ARRAY_SPEC_CONST_UNUSED_H
uint32_t size; uint32_t size;
USE_OPLINE USE_OPLINE
SAVE_OPLINE();
array = EX_VAR(opline->result.var); array = EX_VAR(opline->result.var);
if (IS_CONST != IS_UNUSED) { if (IS_CONST != IS_UNUSED) {
size = opline->extended_value >> ZEND_ARRAY_SIZE_SHIFT; size = opline->extended_value >> ZEND_ARRAY_SIZE_SHIFT;
@ -12734,6 +12737,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_INIT_ARRAY_SPEC_CONST_CV_HANDL
uint32_t size; uint32_t size;
USE_OPLINE USE_OPLINE
SAVE_OPLINE();
array = EX_VAR(opline->result.var); array = EX_VAR(opline->result.var);
if (IS_CONST != IS_UNUSED) { if (IS_CONST != IS_UNUSED) {
size = opline->extended_value >> ZEND_ARRAY_SIZE_SHIFT; size = opline->extended_value >> ZEND_ARRAY_SIZE_SHIFT;
@ -20945,6 +20949,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_INIT_ARRAY_SPEC_TMP_CONST_HAND
uint32_t size; uint32_t size;
USE_OPLINE USE_OPLINE
SAVE_OPLINE();
array = EX_VAR(opline->result.var); array = EX_VAR(opline->result.var);
if (IS_TMP_VAR != IS_UNUSED) { if (IS_TMP_VAR != IS_UNUSED) {
size = opline->extended_value >> ZEND_ARRAY_SIZE_SHIFT; size = opline->extended_value >> ZEND_ARRAY_SIZE_SHIFT;
@ -21385,6 +21390,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_INIT_ARRAY_SPEC_TMP_TMPVAR_HAN
uint32_t size; uint32_t size;
USE_OPLINE USE_OPLINE
SAVE_OPLINE();
array = EX_VAR(opline->result.var); array = EX_VAR(opline->result.var);
if (IS_TMP_VAR != IS_UNUSED) { if (IS_TMP_VAR != IS_UNUSED) {
size = opline->extended_value >> ZEND_ARRAY_SIZE_SHIFT; size = opline->extended_value >> ZEND_ARRAY_SIZE_SHIFT;
@ -21841,6 +21847,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_INIT_ARRAY_SPEC_TMP_UNUSED_HAN
uint32_t size; uint32_t size;
USE_OPLINE USE_OPLINE
SAVE_OPLINE();
array = EX_VAR(opline->result.var); array = EX_VAR(opline->result.var);
if (IS_TMP_VAR != IS_UNUSED) { if (IS_TMP_VAR != IS_UNUSED) {
size = opline->extended_value >> ZEND_ARRAY_SIZE_SHIFT; size = opline->extended_value >> ZEND_ARRAY_SIZE_SHIFT;
@ -22241,6 +22248,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_INIT_ARRAY_SPEC_TMP_CV_HANDLER
uint32_t size; uint32_t size;
USE_OPLINE USE_OPLINE
SAVE_OPLINE();
array = EX_VAR(opline->result.var); array = EX_VAR(opline->result.var);
if (IS_TMP_VAR != IS_UNUSED) { if (IS_TMP_VAR != IS_UNUSED) {
size = opline->extended_value >> ZEND_ARRAY_SIZE_SHIFT; size = opline->extended_value >> ZEND_ARRAY_SIZE_SHIFT;
@ -26108,6 +26116,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_INIT_ARRAY_SPEC_VAR_CONST_HAND
uint32_t size; uint32_t size;
USE_OPLINE USE_OPLINE
SAVE_OPLINE();
array = EX_VAR(opline->result.var); array = EX_VAR(opline->result.var);
if (IS_VAR != IS_UNUSED) { if (IS_VAR != IS_UNUSED) {
size = opline->extended_value >> ZEND_ARRAY_SIZE_SHIFT; size = opline->extended_value >> ZEND_ARRAY_SIZE_SHIFT;
@ -28625,6 +28634,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_INIT_ARRAY_SPEC_VAR_TMPVAR_HAN
uint32_t size; uint32_t size;
USE_OPLINE USE_OPLINE
SAVE_OPLINE();
array = EX_VAR(opline->result.var); array = EX_VAR(opline->result.var);
if (IS_VAR != IS_UNUSED) { if (IS_VAR != IS_UNUSED) {
size = opline->extended_value >> ZEND_ARRAY_SIZE_SHIFT; size = opline->extended_value >> ZEND_ARRAY_SIZE_SHIFT;
@ -30698,6 +30708,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_INIT_ARRAY_SPEC_VAR_UNUSED_HAN
uint32_t size; uint32_t size;
USE_OPLINE USE_OPLINE
SAVE_OPLINE();
array = EX_VAR(opline->result.var); array = EX_VAR(opline->result.var);
if (IS_VAR != IS_UNUSED) { if (IS_VAR != IS_UNUSED) {
size = opline->extended_value >> ZEND_ARRAY_SIZE_SHIFT; size = opline->extended_value >> ZEND_ARRAY_SIZE_SHIFT;
@ -33073,6 +33084,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_INIT_ARRAY_SPEC_VAR_CV_HANDLER
uint32_t size; uint32_t size;
USE_OPLINE USE_OPLINE
SAVE_OPLINE();
array = EX_VAR(opline->result.var); array = EX_VAR(opline->result.var);
if (IS_VAR != IS_UNUSED) { if (IS_VAR != IS_UNUSED) {
size = opline->extended_value >> ZEND_ARRAY_SIZE_SHIFT; size = opline->extended_value >> ZEND_ARRAY_SIZE_SHIFT;
@ -35423,6 +35435,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_INIT_ARRAY_SPEC_UNUSED_CONST_H
uint32_t size; uint32_t size;
USE_OPLINE USE_OPLINE
SAVE_OPLINE();
array = EX_VAR(opline->result.var); array = EX_VAR(opline->result.var);
if (IS_UNUSED != IS_UNUSED) { if (IS_UNUSED != IS_UNUSED) {
size = opline->extended_value >> ZEND_ARRAY_SIZE_SHIFT; size = opline->extended_value >> ZEND_ARRAY_SIZE_SHIFT;
@ -37421,6 +37434,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_INIT_ARRAY_SPEC_UNUSED_TMPVAR_
uint32_t size; uint32_t size;
USE_OPLINE USE_OPLINE
SAVE_OPLINE();
array = EX_VAR(opline->result.var); array = EX_VAR(opline->result.var);
if (IS_UNUSED != IS_UNUSED) { if (IS_UNUSED != IS_UNUSED) {
size = opline->extended_value >> ZEND_ARRAY_SIZE_SHIFT; size = opline->extended_value >> ZEND_ARRAY_SIZE_SHIFT;
@ -38053,6 +38067,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_INIT_ARRAY_SPEC_UNUSED_UNUSED_
uint32_t size; uint32_t size;
USE_OPLINE USE_OPLINE
SAVE_OPLINE();
array = EX_VAR(opline->result.var); array = EX_VAR(opline->result.var);
if (IS_UNUSED != IS_UNUSED) { if (IS_UNUSED != IS_UNUSED) {
size = opline->extended_value >> ZEND_ARRAY_SIZE_SHIFT; size = opline->extended_value >> ZEND_ARRAY_SIZE_SHIFT;
@ -40065,6 +40080,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_INIT_ARRAY_SPEC_UNUSED_CV_HAND
uint32_t size; uint32_t size;
USE_OPLINE USE_OPLINE
SAVE_OPLINE();
array = EX_VAR(opline->result.var); array = EX_VAR(opline->result.var);
if (IS_UNUSED != IS_UNUSED) { if (IS_UNUSED != IS_UNUSED) {
size = opline->extended_value >> ZEND_ARRAY_SIZE_SHIFT; size = opline->extended_value >> ZEND_ARRAY_SIZE_SHIFT;
@ -41800,7 +41816,6 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_BIND_STATIC_SPEC_CV_HANDLER(ZE
value = (zval*)((char*)ht->arData + (opline->extended_value & ~(ZEND_BIND_REF|ZEND_BIND_IMPLICIT|ZEND_BIND_EXPLICIT))); value = (zval*)((char*)ht->arData + (opline->extended_value & ~(ZEND_BIND_REF|ZEND_BIND_IMPLICIT|ZEND_BIND_EXPLICIT)));
if (opline->extended_value & ZEND_BIND_REF) { if (opline->extended_value & ZEND_BIND_REF) {
i_zval_ptr_dtor(variable_ptr);
if (UNEXPECTED(!Z_ISREF_P(value))) { if (UNEXPECTED(!Z_ISREF_P(value))) {
zend_reference *ref = (zend_reference*)emalloc(sizeof(zend_reference)); zend_reference *ref = (zend_reference*)emalloc(sizeof(zend_reference));
GC_SET_REFCOUNT(ref, 2); GC_SET_REFCOUNT(ref, 2);
@ -41815,9 +41830,11 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_BIND_STATIC_SPEC_CV_HANDLER(ZE
ref->sources.ptr = NULL; ref->sources.ptr = NULL;
Z_REF_P(value) = ref; Z_REF_P(value) = ref;
Z_TYPE_INFO_P(value) = IS_REFERENCE_EX; Z_TYPE_INFO_P(value) = IS_REFERENCE_EX;
i_zval_ptr_dtor(variable_ptr);
ZVAL_REF(variable_ptr, ref); ZVAL_REF(variable_ptr, ref);
} else { } else {
Z_ADDREF_P(value); Z_ADDREF_P(value);
i_zval_ptr_dtor(variable_ptr);
ZVAL_REF(variable_ptr, Z_REF_P(value)); ZVAL_REF(variable_ptr, Z_REF_P(value));
if (opline->op2_type != IS_UNUSED) { if (opline->op2_type != IS_UNUSED) {
FREE_OP(opline->op2_type, opline->op2.var); FREE_OP(opline->op2_type, opline->op2.var);
@ -45241,6 +45258,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_INIT_ARRAY_SPEC_CV_CONST_HANDL
uint32_t size; uint32_t size;
USE_OPLINE USE_OPLINE
SAVE_OPLINE();
array = EX_VAR(opline->result.var); array = EX_VAR(opline->result.var);
if (IS_CV != IS_UNUSED) { if (IS_CV != IS_UNUSED) {
size = opline->extended_value >> ZEND_ARRAY_SIZE_SHIFT; size = opline->extended_value >> ZEND_ARRAY_SIZE_SHIFT;
@ -48994,6 +49012,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_INIT_ARRAY_SPEC_CV_TMPVAR_HAND
uint32_t size; uint32_t size;
USE_OPLINE USE_OPLINE
SAVE_OPLINE();
array = EX_VAR(opline->result.var); array = EX_VAR(opline->result.var);
if (IS_CV != IS_UNUSED) { if (IS_CV != IS_UNUSED) {
size = opline->extended_value >> ZEND_ARRAY_SIZE_SHIFT; size = opline->extended_value >> ZEND_ARRAY_SIZE_SHIFT;
@ -50957,6 +50976,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_INIT_ARRAY_SPEC_CV_UNUSED_HAND
uint32_t size; uint32_t size;
USE_OPLINE USE_OPLINE
SAVE_OPLINE();
array = EX_VAR(opline->result.var); array = EX_VAR(opline->result.var);
if (IS_CV != IS_UNUSED) { if (IS_CV != IS_UNUSED) {
size = opline->extended_value >> ZEND_ARRAY_SIZE_SHIFT; size = opline->extended_value >> ZEND_ARRAY_SIZE_SHIFT;
@ -54588,6 +54608,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_INIT_ARRAY_SPEC_CV_CV_HANDLER(
uint32_t size; uint32_t size;
USE_OPLINE USE_OPLINE
SAVE_OPLINE();
array = EX_VAR(opline->result.var); array = EX_VAR(opline->result.var);
if (IS_CV != IS_UNUSED) { if (IS_CV != IS_UNUSED) {
size = opline->extended_value >> ZEND_ARRAY_SIZE_SHIFT; size = opline->extended_value >> ZEND_ARRAY_SIZE_SHIFT;