diff --git a/Zend/zend_vm_def.h b/Zend/zend_vm_def.h index 5a7e6d6d1165f..42e2590b4602f 100644 --- a/Zend/zend_vm_def.h +++ b/Zend/zend_vm_def.h @@ -4209,7 +4209,7 @@ ZEND_VM_HOT_HANDLER(130, ZEND_DO_UCALL, ANY, ANY, SPEC(RETVAL,OBSERVER)) call->prev_execute_data = execute_data; execute_data = call; - i_init_func_execute_data(&fbc->op_array, ret, 0 EXECUTE_DATA_CC); + i_init_func_execute_data(&fbc->op_array, ret, 1 EXECUTE_DATA_CC); LOAD_OPLINE_EX(); ZEND_OBSERVER_SAVE_OPLINE(); ZEND_OBSERVER_FCALL_BEGIN(execute_data); diff --git a/Zend/zend_vm_execute.h b/Zend/zend_vm_execute.h index a2a064377d8c4..b7c59ef03dc50 100644 --- a/Zend/zend_vm_execute.h +++ b/Zend/zend_vm_execute.h @@ -1513,7 +1513,7 @@ static ZEND_VM_HOT ZEND_OPCODE_HANDLER_RET ZEND_OPCODE_HANDLER_FUNC_CCONV ZEND_D call->prev_execute_data = execute_data; execute_data = call; - i_init_func_execute_data(&fbc->op_array, ret, 0 EXECUTE_DATA_CC); + i_init_func_execute_data(&fbc->op_array, ret, 1 EXECUTE_DATA_CC); LOAD_OPLINE_EX(); @@ -1539,7 +1539,7 @@ static ZEND_VM_HOT ZEND_OPCODE_HANDLER_RET ZEND_OPCODE_HANDLER_FUNC_CCONV ZEND_D call->prev_execute_data = execute_data; execute_data = call; - i_init_func_execute_data(&fbc->op_array, ret, 0 EXECUTE_DATA_CC); + i_init_func_execute_data(&fbc->op_array, ret, 1 EXECUTE_DATA_CC); LOAD_OPLINE_EX(); @@ -1565,7 +1565,7 @@ static ZEND_VM_COLD ZEND_OPCODE_HANDLER_RET ZEND_OPCODE_HANDLER_FUNC_CCONV ZEND_ call->prev_execute_data = execute_data; execute_data = call; - i_init_func_execute_data(&fbc->op_array, ret, 0 EXECUTE_DATA_CC); + i_init_func_execute_data(&fbc->op_array, ret, 1 EXECUTE_DATA_CC); LOAD_OPLINE_EX(); SAVE_OPLINE(); zend_observer_fcall_begin_specialized(execute_data, false); @@ -54265,7 +54265,7 @@ static ZEND_VM_HOT ZEND_OPCODE_HANDLER_RET ZEND_OPCODE_HANDLER_CCONV ZEND_DO_UCA call->prev_execute_data = execute_data; execute_data = call; - i_init_func_execute_data(&fbc->op_array, ret, 0 EXECUTE_DATA_CC); + i_init_func_execute_data(&fbc->op_array, ret, 1 EXECUTE_DATA_CC); LOAD_OPLINE_EX(); @@ -54291,7 +54291,7 @@ static ZEND_VM_HOT ZEND_OPCODE_HANDLER_RET ZEND_OPCODE_HANDLER_CCONV ZEND_DO_UCA call->prev_execute_data = execute_data; execute_data = call; - i_init_func_execute_data(&fbc->op_array, ret, 0 EXECUTE_DATA_CC); + i_init_func_execute_data(&fbc->op_array, ret, 1 EXECUTE_DATA_CC); LOAD_OPLINE_EX(); @@ -54317,7 +54317,7 @@ static ZEND_VM_COLD ZEND_OPCODE_HANDLER_RET ZEND_OPCODE_HANDLER_CCONV ZEND_DO_UC call->prev_execute_data = execute_data; execute_data = call; - i_init_func_execute_data(&fbc->op_array, ret, 0 EXECUTE_DATA_CC); + i_init_func_execute_data(&fbc->op_array, ret, 1 EXECUTE_DATA_CC); LOAD_OPLINE_EX(); SAVE_OPLINE(); zend_observer_fcall_begin_specialized(execute_data, false); diff --git a/ext/opcache/tests/func_call_ref_return_overridden.phpt b/ext/opcache/tests/func_call_ref_return_overridden.phpt new file mode 100644 index 0000000000000..0f1e5cf095218 --- /dev/null +++ b/ext/opcache/tests/func_call_ref_return_overridden.phpt @@ -0,0 +1,41 @@ +--TEST-- +DO_UCALL must not be used for functions returning by reference +--DESCRIPTION-- +The optimizer's zend_get_call_op() converts DO_FCALL to DO_UCALL for user +functions, but DO_UCALL hardcodes return_reference=0 in +i_init_func_execute_data(). When the called function returns by reference +(e.g. an overridden method using ASSIGN_REF), this produces invalid opcode +sequences. The fix is either to not use DO_UCALL when the function has +ZEND_ACC_RETURN_REFERENCE, or to make DO_UCALL honor it. +--FILE-- +getData() && !isset($data['key'])) { + // unreachable + } + return $data; + } +} + +class Child extends Base { + protected function &getData(): array { + static $x = ['value' => 42]; + return $x; + } +} + +$child = new Child(); +$result = $child->process(); +var_dump($result); +?> +--EXPECT-- +array(1) { + ["value"]=> + int(42) +}