]> granicus.if.org Git - php/commitdiff
Fix return type separation with references. It now includes a check in the opcode...
authorAnthony Ferrara <ircmaxell@gmail.com>
Wed, 18 Mar 2015 22:10:08 +0000 (18:10 -0400)
committerAnthony Ferrara <ircmaxell@gmail.com>
Wed, 18 Mar 2015 22:10:08 +0000 (18:10 -0400)
Zend/tests/return_types/return_reference_separation.phpt [new file with mode: 0644]
Zend/zend_compile.c
Zend/zend_compile.h
Zend/zend_execute.c
Zend/zend_vm_def.h
Zend/zend_vm_execute.h

diff --git a/Zend/tests/return_types/return_reference_separation.phpt b/Zend/tests/return_types/return_reference_separation.phpt
new file mode 100644 (file)
index 0000000..62dafed
--- /dev/null
@@ -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)
\ No newline at end of file
index c44790dd9e089807ceadb4c84794037efcc79223..5744ae3ad0fbb214ae471b426b123450b05a61ef 100644 (file)
@@ -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 "
index 3e1b10870cc1a87174d15d5a57c9e448e74caa03..2de832854c14fcb68ec6c3ad6b7878dee8c7ecb7 100644 (file)
@@ -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)
 
index a6170c7c62671ce2d2399be265b86d3bd9da1e82..b6d4816d3ce341b92469629e67bccb1b66e78329 100644 (file)
@@ -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;
-                       }
                }
        }
 }
index 0643995314dd8d85b52db3780a927229fa9f684d..d116c4f5d6c331470ca8b7af65a1f8ee386faf05 100644 (file)
@@ -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();
index 72d3fedfb23a12fae97a5df90c0bd8734201f4b7..d535b41dca4e513787569a4ef5bd0d63677fae00 100644 (file)
@@ -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();