From: Anthony Ferrara Date: Wed, 18 Mar 2015 22:10:08 +0000 (-0400) Subject: Fix return type separation with references. It now includes a check in the opcode... X-Git-Tag: PRE_PHP7_NSAPI_REMOVAL~573^2~11^2~9 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=427ecdc5eb1ca29209384e770e56018632b5f9ac;p=php Fix return type separation with references. It now includes a check in the opcode handler and properly separates the value in both cases --- diff --git a/Zend/tests/return_types/return_reference_separation.phpt b/Zend/tests/return_types/return_reference_separation.phpt new file mode 100644 index 0000000000..62dafeda33 --- /dev/null +++ b/Zend/tests/return_types/return_reference_separation.phpt @@ -0,0 +1,26 @@ +--TEST-- +Return value separation + +--FILE-- + +--EXPECTF-- +string(3) "123" +int(123) +string(3) "123" +int(123) \ No newline at end of file diff --git a/Zend/zend_compile.c b/Zend/zend_compile.c index c44790dd9e..5744ae3ad0 100644 --- a/Zend/zend_compile.c +++ b/Zend/zend_compile.c @@ -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); - } - - arg_info->type_hint = IS_OBJECT; - arg_info->class_name = 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); + } -done: + arg_info->type_hint = IS_OBJECT; + arg_info->class_name = class_name; + } 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 " diff --git a/Zend/zend_compile.h b/Zend/zend_compile.h index 3e1b10870c..2de832854c 100644 --- a/Zend/zend_compile.h +++ b/Zend/zend_compile.h @@ -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) diff --git a/Zend/zend_execute.c b/Zend/zend_execute.c index a6170c7c62..b6d4816d3c 100644 --- a/Zend/zend_execute.c +++ b/Zend/zend_execute.c @@ -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; - } } } } diff --git a/Zend/zend_vm_def.h b/Zend/zend_vm_def.h index 0643995314..d116c4f5d6 100644 --- a/Zend/zend_vm_def.h +++ b/Zend/zend_vm_def.h @@ -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(); diff --git a/Zend/zend_vm_execute.h b/Zend/zend_vm_execute.h index 72d3fedfb2..d535b41dca 100644 --- a/Zend/zend_vm_execute.h +++ b/Zend/zend_vm_execute.h @@ -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();