mirror of
https://github.com/php/php-src.git
synced 2026-04-26 09:28:21 +02:00
Fix return type separation with references. It now includes a check in the opcode handler and properly separates the value in both cases
This commit is contained in:
@@ -0,0 +1,26 @@
|
||||
--TEST--
|
||||
Return value separation
|
||||
|
||||
--FILE--
|
||||
<?php
|
||||
function test1(&$abc) : string {
|
||||
return $abc;
|
||||
}
|
||||
|
||||
function &test2(int $abc) : string {
|
||||
return $abc;
|
||||
}
|
||||
|
||||
$a = 123;
|
||||
|
||||
var_dump(test1($a));
|
||||
var_dump($a);
|
||||
var_dump(test2($a));
|
||||
var_dump($a);
|
||||
|
||||
?>
|
||||
--EXPECTF--
|
||||
string(3) "123"
|
||||
int(123)
|
||||
string(3) "123"
|
||||
int(123)
|
||||
+13
-12
@@ -1922,9 +1922,12 @@ static zend_op *zend_delayed_compile_end(uint32_t offset) /* {{{ */
|
||||
|
||||
static void zend_emit_return_type_check(znode *expr, zend_arg_info *return_info) /* {{{ */
|
||||
{
|
||||
zend_bool returns_reference = (CG(active_op_array)->fn_flags & ZEND_ACC_RETURN_REFERENCE) != 0;
|
||||
|
||||
if (return_info->type_hint != IS_UNDEF) {
|
||||
zend_op *opline = zend_emit_op(NULL, ZEND_VERIFY_RETURN_TYPE, expr, NULL);
|
||||
opline->extended_value = CG(declarables).strict_types;
|
||||
opline->extended_value = (CG(declarables).strict_types ? ZEND_RETURN_TYPE_STRICT : 0)
|
||||
& (returns_reference ? ZEND_RETURN_TYPE_BYREF : 0);
|
||||
}
|
||||
}
|
||||
/* }}} */
|
||||
@@ -4224,19 +4227,17 @@ void zend_compile_params(zend_ast *ast, zend_ast *return_type_ast, zend_bool is_
|
||||
type = zend_lookup_scalar_typehint_by_name(class_name);
|
||||
if (type != 0) {
|
||||
arg_info->type_hint = type;
|
||||
goto done;
|
||||
}
|
||||
|
||||
if (zend_is_const_default_class_ref(type_ast)) {
|
||||
class_name = zend_resolve_class_name_ast(type_ast);
|
||||
} else {
|
||||
zend_string_addref(class_name);
|
||||
|
||||
if (zend_is_const_default_class_ref(type_ast)) {
|
||||
class_name = zend_resolve_class_name_ast(type_ast);
|
||||
} else {
|
||||
zend_string_addref(class_name);
|
||||
}
|
||||
|
||||
arg_info->type_hint = IS_OBJECT;
|
||||
arg_info->class_name = class_name;
|
||||
}
|
||||
|
||||
arg_info->type_hint = IS_OBJECT;
|
||||
arg_info->class_name = class_name;
|
||||
|
||||
done:
|
||||
if (default_ast && !has_null_default && !Z_CONSTANT(default_node.u.constant)) {
|
||||
if (arg_info->class_name) {
|
||||
zend_error_noreturn(E_COMPILE_ERROR, "Default value for parameters "
|
||||
|
||||
@@ -425,6 +425,9 @@ struct _zend_execute_data {
|
||||
#define ZEND_CALL_CTOR_RESULT_UNUSED (1 << 4)
|
||||
#define ZEND_CALL_STRICT_TYPEHINTS (1 << 5)
|
||||
|
||||
#define ZEND_RETURN_TYPE_STRICT (1 << 0)
|
||||
#define ZEND_RETURN_TYPE_BYREF (1 << 1)
|
||||
|
||||
#define ZEND_CALL_INFO(call) \
|
||||
(Z_TYPE_INFO((call)->This) >> 24)
|
||||
|
||||
|
||||
+4
-8
@@ -736,16 +736,12 @@ static void zend_verify_internal_arg_type(zend_function *zf, uint32_t arg_num, z
|
||||
zend_verify_arg_error(zf, arg_num, "be callable", "", zend_zval_type_name(arg), "", arg);
|
||||
}
|
||||
} else if (UNEXPECTED(!ZEND_SAME_FAKE_TYPE(cur_arg_info->type_hint, Z_TYPE_P(arg)))) {
|
||||
if (Z_TYPE_P(arg) == IS_NULL) {
|
||||
if (!cur_arg_info->allow_null) {
|
||||
failure:
|
||||
zend_verify_arg_error(zf, arg_num, "be of the type ", zend_get_type_by_const(cur_arg_info->type_hint), zend_zval_type_name(arg), "", arg);
|
||||
}
|
||||
if ((Z_TYPE_P(arg) == IS_NULL && !cur_arg_info->allow_null)
|
||||
|| !zend_verify_scalar_type_hint(cur_arg_info->type_hint, arg, strict)) {
|
||||
|
||||
zend_verify_arg_error(zf, arg_num, "be of the type ", zend_get_type_by_const(cur_arg_info->type_hint), zend_zval_type_name(arg), "", arg);
|
||||
return;
|
||||
}
|
||||
if (!zend_verify_scalar_type_hint(cur_arg_info->type_hint, arg, strict)) {
|
||||
goto failure;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+11
-3
@@ -3606,9 +3606,17 @@ ZEND_VM_HANDLER(124, ZEND_VERIFY_RETURN_TYPE, CONST|TMP|VAR|UNUSED|CV, UNUSED)
|
||||
zval *retval_ptr;
|
||||
zend_free_op free_op1;
|
||||
|
||||
retval_ptr = GET_OP1_ZVAL_PTR_DEREF(BP_VAR_R);
|
||||
/* extended_value stores strictness flag */
|
||||
zend_verify_return_type(EX(func), retval_ptr, opline->extended_value);
|
||||
retval_ptr = GET_OP1_ZVAL_PTR(BP_VAR_R);
|
||||
|
||||
if (EXPECTED((opline->extended_value & ZEND_RETURN_TYPE_BYREF) == 0)) {
|
||||
/* Does not return by reference */
|
||||
SEPARATE_ZVAL(retval_ptr);
|
||||
} else {
|
||||
ZVAL_DEREF(retval_ptr);
|
||||
SEPARATE_ZVAL_NOREF(retval_ptr);
|
||||
}
|
||||
|
||||
zend_verify_return_type(EX(func), retval_ptr, opline->extended_value & ZEND_RETURN_TYPE_STRICT);
|
||||
#endif
|
||||
}
|
||||
CHECK_EXCEPTION();
|
||||
|
||||
+52
-12
@@ -6976,8 +6976,16 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_VERIFY_RETURN_TYPE_SPEC_CONST_
|
||||
|
||||
|
||||
retval_ptr = EX_CONSTANT(opline->op1);
|
||||
/* extended_value stores strictness flag */
|
||||
zend_verify_return_type(EX(func), retval_ptr, opline->extended_value);
|
||||
|
||||
if (EXPECTED((opline->extended_value & ZEND_RETURN_TYPE_BYREF) == 0)) {
|
||||
/* Does not return by reference */
|
||||
SEPARATE_ZVAL(retval_ptr);
|
||||
} else {
|
||||
ZVAL_DEREF(retval_ptr);
|
||||
SEPARATE_ZVAL_NOREF(retval_ptr);
|
||||
}
|
||||
|
||||
zend_verify_return_type(EX(func), retval_ptr, opline->extended_value & ZEND_RETURN_TYPE_STRICT);
|
||||
#endif
|
||||
}
|
||||
CHECK_EXCEPTION();
|
||||
@@ -11922,8 +11930,16 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_VERIFY_RETURN_TYPE_SPEC_TMP_UN
|
||||
zend_free_op free_op1;
|
||||
|
||||
retval_ptr = _get_zval_ptr_tmp(opline->op1.var, execute_data, &free_op1);
|
||||
/* extended_value stores strictness flag */
|
||||
zend_verify_return_type(EX(func), retval_ptr, opline->extended_value);
|
||||
|
||||
if (EXPECTED((opline->extended_value & ZEND_RETURN_TYPE_BYREF) == 0)) {
|
||||
/* Does not return by reference */
|
||||
SEPARATE_ZVAL(retval_ptr);
|
||||
} else {
|
||||
ZVAL_DEREF(retval_ptr);
|
||||
SEPARATE_ZVAL_NOREF(retval_ptr);
|
||||
}
|
||||
|
||||
zend_verify_return_type(EX(func), retval_ptr, opline->extended_value & ZEND_RETURN_TYPE_STRICT);
|
||||
#endif
|
||||
}
|
||||
CHECK_EXCEPTION();
|
||||
@@ -17267,9 +17283,17 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_VERIFY_RETURN_TYPE_SPEC_VAR_UN
|
||||
zval *retval_ptr;
|
||||
zend_free_op free_op1;
|
||||
|
||||
retval_ptr = _get_zval_ptr_var_deref(opline->op1.var, execute_data, &free_op1);
|
||||
/* extended_value stores strictness flag */
|
||||
zend_verify_return_type(EX(func), retval_ptr, opline->extended_value);
|
||||
retval_ptr = _get_zval_ptr_var(opline->op1.var, execute_data, &free_op1);
|
||||
|
||||
if (EXPECTED((opline->extended_value & ZEND_RETURN_TYPE_BYREF) == 0)) {
|
||||
/* Does not return by reference */
|
||||
SEPARATE_ZVAL(retval_ptr);
|
||||
} else {
|
||||
ZVAL_DEREF(retval_ptr);
|
||||
SEPARATE_ZVAL_NOREF(retval_ptr);
|
||||
}
|
||||
|
||||
zend_verify_return_type(EX(func), retval_ptr, opline->extended_value & ZEND_RETURN_TYPE_STRICT);
|
||||
#endif
|
||||
}
|
||||
CHECK_EXCEPTION();
|
||||
@@ -22871,8 +22895,16 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_VERIFY_RETURN_TYPE_SPEC_UNUSED
|
||||
|
||||
|
||||
retval_ptr = NULL;
|
||||
/* extended_value stores strictness flag */
|
||||
zend_verify_return_type(EX(func), retval_ptr, opline->extended_value);
|
||||
|
||||
if (EXPECTED((opline->extended_value & ZEND_RETURN_TYPE_BYREF) == 0)) {
|
||||
/* Does not return by reference */
|
||||
SEPARATE_ZVAL(retval_ptr);
|
||||
} else {
|
||||
ZVAL_DEREF(retval_ptr);
|
||||
SEPARATE_ZVAL_NOREF(retval_ptr);
|
||||
}
|
||||
|
||||
zend_verify_return_type(EX(func), retval_ptr, opline->extended_value & ZEND_RETURN_TYPE_STRICT);
|
||||
#endif
|
||||
}
|
||||
CHECK_EXCEPTION();
|
||||
@@ -31800,9 +31832,17 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_VERIFY_RETURN_TYPE_SPEC_CV_UNU
|
||||
zval *retval_ptr;
|
||||
|
||||
|
||||
retval_ptr = _get_zval_ptr_cv_deref_BP_VAR_R(execute_data, opline->op1.var);
|
||||
/* extended_value stores strictness flag */
|
||||
zend_verify_return_type(EX(func), retval_ptr, opline->extended_value);
|
||||
retval_ptr = _get_zval_ptr_cv_BP_VAR_R(execute_data, opline->op1.var);
|
||||
|
||||
if (EXPECTED((opline->extended_value & ZEND_RETURN_TYPE_BYREF) == 0)) {
|
||||
/* Does not return by reference */
|
||||
SEPARATE_ZVAL(retval_ptr);
|
||||
} else {
|
||||
ZVAL_DEREF(retval_ptr);
|
||||
SEPARATE_ZVAL_NOREF(retval_ptr);
|
||||
}
|
||||
|
||||
zend_verify_return_type(EX(func), retval_ptr, opline->extended_value & ZEND_RETURN_TYPE_STRICT);
|
||||
#endif
|
||||
}
|
||||
CHECK_EXCEPTION();
|
||||
|
||||
Reference in New Issue
Block a user