]> granicus.if.org Git - php/commitdiff
Fix bug #68446 (bug with constant defaults and type hints)
authorBob Weinand <bobwei9@hotmail.com>
Sun, 23 Nov 2014 20:09:31 +0000 (21:09 +0100)
committerBob Weinand <bobwei9@hotmail.com>
Sun, 23 Nov 2014 20:10:41 +0000 (21:10 +0100)
Zend/tests/class_constants_002.phpt
Zend/zend_compile.c
Zend/zend_execute.c
Zend/zend_vm_def.h
Zend/zend_vm_execute.h

index 9aad8088da800e350d1025d4a9630d815402ef89..75d1032e54508f531d57fd61ff936482c9566343 100644 (file)
@@ -26,6 +26,5 @@ echo "Done\n";
 --EXPECTF--    
 int(1)
 int(5)
-int(10)
 
 Fatal error: Class 'NoSuchClass' not found in %s on line %d
index 8e416ea0a596adf74d43de0674087ddb5afbbe35..e023b24a8eba4ef11b27d402d6a156443a82edc9 100644 (file)
@@ -1931,8 +1931,8 @@ void zend_do_receive_param(zend_uchar op, znode *varname, const znode *initializ
                        if (class_type->u.constant.type == IS_ARRAY) {
                                cur_arg_info->type_hint = IS_ARRAY;
                                if (op == ZEND_RECV_INIT) {
-                                       if (Z_TYPE(initialization->u.constant) == IS_NULL || (Z_TYPE(initialization->u.constant) == IS_CONSTANT && !strcasecmp(Z_STRVAL(initialization->u.constant), "NULL")) || Z_TYPE(initialization->u.constant) == IS_CONSTANT_AST) {
-                                               cur_arg_info->allow_null = 1;
+                                       if (Z_TYPE(initialization->u.constant) == IS_NULL || (Z_TYPE(initialization->u.constant) & IS_CONSTANT_TYPE_MASK) == IS_CONSTANT || (Z_TYPE(initialization->u.constant) & IS_CONSTANT_TYPE_MASK) == IS_CONSTANT_AST) {
+                                               cur_arg_info->allow_null = (Z_TYPE(initialization->u.constant) != IS_NULL) + 1;
                                        } else if (Z_TYPE(initialization->u.constant) != IS_ARRAY) {
                                                zend_error_noreturn(E_COMPILE_ERROR, "Default value for parameters with array type hint can only be an array or NULL");
                                        }
@@ -1940,8 +1940,8 @@ void zend_do_receive_param(zend_uchar op, znode *varname, const znode *initializ
                        } else if (class_type->u.constant.type == IS_CALLABLE) {
                                cur_arg_info->type_hint = IS_CALLABLE;
                                if (op == ZEND_RECV_INIT) {
-                                       if (Z_TYPE(initialization->u.constant) == IS_NULL || (Z_TYPE(initialization->u.constant) == IS_CONSTANT && !strcasecmp(Z_STRVAL(initialization->u.constant), "NULL")) || Z_TYPE(initialization->u.constant) == IS_CONSTANT_AST) {
-                                               cur_arg_info->allow_null = 1;
+                                       if (Z_TYPE(initialization->u.constant) == IS_NULL || (Z_TYPE(initialization->u.constant) & IS_CONSTANT_TYPE_MASK) == IS_CONSTANT || (Z_TYPE(initialization->u.constant) & IS_CONSTANT_TYPE_MASK) == IS_CONSTANT_AST) {
+                                               cur_arg_info->allow_null = (Z_TYPE(initialization->u.constant) != IS_NULL) + 1;
                                        } else {
                                                zend_error_noreturn(E_COMPILE_ERROR, "Default value for parameters with callable type hint can only be NULL");
                                        }
index 6ada04e1cb5c5f4ea15876550e1aff1e5f921a17..081af81d507690d19a2c329dbb65f550f22ee67d 100644 (file)
@@ -608,7 +608,17 @@ ZEND_API int zend_verify_arg_error(int error_type, const zend_function *zf, zend
        return 0;
 }
 
-static inline int zend_verify_arg_type(zend_function *zf, zend_uint arg_num, zval *arg, ulong fetch_type TSRMLS_DC)
+static inline int zend_arg_allows_null(zend_bool allow_null, zval *default_value TSRMLS_DC)
+{
+       if (allow_null < 2 || !default_value) {
+               return allow_null;
+       }
+
+       /* assuming update_constant_ex done before */
+       return Z_TYPE_P(default_value) == IS_NULL;
+}
+
+static inline int zend_verify_arg_type(zend_function *zf, zend_uint arg_num, zval *arg, zval *defaultval, ulong fetch_type TSRMLS_DC)
 {
        zend_arg_info *cur_arg_info;
        char *need_msg;
@@ -638,7 +648,7 @@ static inline int zend_verify_arg_type(zend_function *zf, zend_uint arg_num, zva
                        if (!ce || !instanceof_function(Z_OBJCE_P(arg), ce TSRMLS_CC)) {
                                return zend_verify_arg_error(E_RECOVERABLE_ERROR, zf, arg_num, need_msg, class_name, "instance of ", Z_OBJCE_P(arg)->name TSRMLS_CC);
                        }
-               } else if (Z_TYPE_P(arg) != IS_NULL || !cur_arg_info->allow_null) {
+               } else if (Z_TYPE_P(arg) != IS_NULL || !zend_arg_allows_null(cur_arg_info->allow_null, defaultval TSRMLS_CC)) {
                        need_msg = zend_verify_arg_class_kind(cur_arg_info, fetch_type, &class_name, &ce TSRMLS_CC);
                        return zend_verify_arg_error(E_RECOVERABLE_ERROR, zf, arg_num, need_msg, class_name, zend_zval_type_name(arg), "" TSRMLS_CC);
                }
@@ -649,7 +659,7 @@ static inline int zend_verify_arg_type(zend_function *zf, zend_uint arg_num, zva
                                        return zend_verify_arg_error(E_RECOVERABLE_ERROR, zf, arg_num, "be of the type array", "", "none", "" TSRMLS_CC);
                                }
 
-                               if (Z_TYPE_P(arg) != IS_ARRAY && (Z_TYPE_P(arg) != IS_NULL || !cur_arg_info->allow_null)) {
+                               if (Z_TYPE_P(arg) != IS_ARRAY && (Z_TYPE_P(arg) != IS_NULL || !zend_arg_allows_null(cur_arg_info->allow_null, defaultval TSRMLS_CC))) {
                                        return zend_verify_arg_error(E_RECOVERABLE_ERROR, zf, arg_num, "be of the type array", "", zend_zval_type_name(arg), "" TSRMLS_CC);
                                }
                                break;
@@ -658,7 +668,7 @@ static inline int zend_verify_arg_type(zend_function *zf, zend_uint arg_num, zva
                                if (!arg) {
                                        return zend_verify_arg_error(E_RECOVERABLE_ERROR, zf, arg_num, "be callable", "", "none", "" TSRMLS_CC);
                                }
-                               if (!zend_is_callable(arg, IS_CALLABLE_CHECK_SILENT, NULL TSRMLS_CC) && (Z_TYPE_P(arg) != IS_NULL || !cur_arg_info->allow_null)) {
+                               if (!zend_is_callable(arg, IS_CALLABLE_CHECK_SILENT, NULL TSRMLS_CC) && (Z_TYPE_P(arg) != IS_NULL || !zend_arg_allows_null(cur_arg_info->allow_null, defaultval TSRMLS_CC))) {
                                        return zend_verify_arg_error(E_RECOVERABLE_ERROR, zf, arg_num, "be callable", "", zend_zval_type_name(arg), "" TSRMLS_CC);
                                }
                                break;
index 705e46e7d338ea9891a2a520fa584047997c362e..65981f6f6f22e7dc1c42be998b1d13d352b7bffa 100644 (file)
@@ -1961,7 +1961,7 @@ ZEND_VM_HELPER(zend_do_fcall_common_helper, ANY, ANY)
                        void **p = EX(function_state).arguments - num_args;
 
                        for (i = 0; i < num_args; ++i, ++p) {
-                               zend_verify_arg_type(fbc, i + 1, (zval *) *p, 0 TSRMLS_CC);
+                               zend_verify_arg_type(fbc, i + 1, (zval *) *p, NULL, 0 TSRMLS_CC);
                        }
                }
 
@@ -3374,7 +3374,7 @@ ZEND_VM_HANDLER(63, ZEND_RECV, ANY, ANY)
 
        SAVE_OPLINE();
        if (UNEXPECTED(param == NULL)) {
-               if (zend_verify_arg_type((zend_function *) EG(active_op_array), arg_num, NULL, opline->extended_value TSRMLS_CC)) {
+               if (zend_verify_arg_type((zend_function *) EG(active_op_array), arg_num, NULL, NULL, opline->extended_value TSRMLS_CC)) {
                        const char *space;
                        const char *class_name;
                        zend_execute_data *ptr;
@@ -3396,7 +3396,7 @@ ZEND_VM_HANDLER(63, ZEND_RECV, ANY, ANY)
        } else {
                zval **var_ptr;
 
-               zend_verify_arg_type((zend_function *) EG(active_op_array), arg_num, *param, opline->extended_value TSRMLS_CC);
+               zend_verify_arg_type((zend_function *) EG(active_op_array), arg_num, *param, NULL, opline->extended_value TSRMLS_CC);
                var_ptr = _get_zval_ptr_ptr_cv_BP_VAR_W(execute_data, opline->result.var TSRMLS_CC);
                Z_DELREF_PP(var_ptr);
                *var_ptr = *param;
@@ -3410,27 +3410,34 @@ ZEND_VM_HANDLER(63, ZEND_RECV, ANY, ANY)
 ZEND_VM_HANDLER(64, ZEND_RECV_INIT, ANY, CONST)
 {
        USE_OPLINE
-       zval *assignment_value;
+       zval *assignment_value, *default_val = NULL;
        zend_uint arg_num = opline->op1.num;
        zval **param = zend_vm_stack_get_arg(arg_num TSRMLS_CC);
        zval **var_ptr;
 
        SAVE_OPLINE();
+       if (IS_CONSTANT_TYPE(Z_TYPE_P(opline->op2.zv))) {
+               ALLOC_ZVAL(default_val);
+               *default_val = *opline->op2.zv;
+               Z_SET_REFCOUNT_P(default_val, 1);
+               zval_update_constant(&default_val, 0 TSRMLS_CC);
+       }
        if (param == NULL) {
-               ALLOC_ZVAL(assignment_value);
-               *assignment_value = *opline->op2.zv;
-               if (IS_CONSTANT_TYPE(Z_TYPE_P(assignment_value))) {
-                       Z_SET_REFCOUNT_P(assignment_value, 1);
-                       zval_update_constant(&assignment_value, 0 TSRMLS_CC);
-               } else if (Z_TYPE_P(assignment_value) == IS_ARRAY) {
-                       HashTable *ht;
-
-                       ALLOC_HASHTABLE(ht);
-                       zend_hash_init(ht, zend_hash_num_elements(Z_ARRVAL_P(assignment_value)), NULL, ZVAL_PTR_DTOR, 0);
-                       zend_hash_copy(ht, Z_ARRVAL_P(assignment_value), (copy_ctor_func_t) zval_deep_copy, NULL, sizeof(zval *));
-                       Z_ARRVAL_P(assignment_value) = ht;
+               if (default_val) {
+                       assignment_value = default_val;
                } else {
-                       zval_copy_ctor(assignment_value);
+                       ALLOC_ZVAL(assignment_value);
+                       *assignment_value = *opline->op2.zv;
+                       if (Z_TYPE_P(assignment_value) == IS_ARRAY) {
+                               HashTable *ht;
+
+                               ALLOC_HASHTABLE(ht);
+                               zend_hash_init(ht, zend_hash_num_elements(Z_ARRVAL_P(assignment_value)), NULL, ZVAL_PTR_DTOR, 0);
+                               zend_hash_copy(ht, Z_ARRVAL_P(assignment_value), (copy_ctor_func_t) zval_deep_copy, NULL, sizeof(zval *));
+                               Z_ARRVAL_P(assignment_value) = ht;
+                       } else {
+                               zval_copy_ctor(assignment_value);
+                       }
                }
                INIT_PZVAL(assignment_value);
        } else {
@@ -3438,11 +3445,16 @@ ZEND_VM_HANDLER(64, ZEND_RECV_INIT, ANY, CONST)
                Z_ADDREF_P(assignment_value);
        }
 
-       zend_verify_arg_type((zend_function *) EG(active_op_array), arg_num, assignment_value, opline->extended_value TSRMLS_CC);
+       zend_verify_arg_type((zend_function *) EG(active_op_array), arg_num, assignment_value, default_val, opline->extended_value TSRMLS_CC);
        var_ptr = _get_zval_ptr_ptr_cv_BP_VAR_W(execute_data, opline->result.var TSRMLS_CC);
        zval_ptr_dtor(var_ptr);
        *var_ptr = assignment_value;
 
+       if (default_val && assignment_value != default_val) {
+               zval_dtor(default_val);
+               efree(default_val);
+       }
+
        CHECK_EXCEPTION();
        ZEND_VM_NEXT_OPCODE();
 }
@@ -3469,7 +3481,7 @@ ZEND_VM_HANDLER(164, ZEND_RECV_VARIADIC, ANY, ANY)
 
        for (; arg_num <= arg_count; ++arg_num) {
                zval **param = zend_vm_stack_get_arg(arg_num TSRMLS_CC);
-               zend_verify_arg_type((zend_function *) EG(active_op_array), arg_num, *param, opline->extended_value TSRMLS_CC);
+               zend_verify_arg_type((zend_function *) EG(active_op_array), arg_num, *param, NULL, opline->extended_value TSRMLS_CC);
                zend_hash_next_index_insert(Z_ARRVAL_P(params), param, sizeof(zval *), NULL);
                Z_ADDREF_PP(param);
        }
index 993aaee7474e5a61a5700fa3541d0f2821bd8227..318f903f7764237b62a0521ba023f268eda6f3e4 100644 (file)
@@ -541,7 +541,7 @@ static int ZEND_FASTCALL zend_do_fcall_common_helper_SPEC(ZEND_OPCODE_HANDLER_AR
                        void **p = EX(function_state).arguments - num_args;
 
                        for (i = 0; i < num_args; ++i, ++p) {
-                               zend_verify_arg_type(fbc, i + 1, (zval *) *p, 0 TSRMLS_CC);
+                               zend_verify_arg_type(fbc, i + 1, (zval *) *p, NULL, 0 TSRMLS_CC);
                        }
                }
 
@@ -861,7 +861,7 @@ static int ZEND_FASTCALL  ZEND_RECV_SPEC_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
 
        SAVE_OPLINE();
        if (UNEXPECTED(param == NULL)) {
-               if (zend_verify_arg_type((zend_function *) EG(active_op_array), arg_num, NULL, opline->extended_value TSRMLS_CC)) {
+               if (zend_verify_arg_type((zend_function *) EG(active_op_array), arg_num, NULL, NULL, opline->extended_value TSRMLS_CC)) {
                        const char *space;
                        const char *class_name;
                        zend_execute_data *ptr;
@@ -883,7 +883,7 @@ static int ZEND_FASTCALL  ZEND_RECV_SPEC_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
        } else {
                zval **var_ptr;
 
-               zend_verify_arg_type((zend_function *) EG(active_op_array), arg_num, *param, opline->extended_value TSRMLS_CC);
+               zend_verify_arg_type((zend_function *) EG(active_op_array), arg_num, *param, NULL, opline->extended_value TSRMLS_CC);
                var_ptr = _get_zval_ptr_ptr_cv_BP_VAR_W(execute_data, opline->result.var TSRMLS_CC);
                Z_DELREF_PP(var_ptr);
                *var_ptr = *param;
@@ -916,7 +916,7 @@ static int ZEND_FASTCALL  ZEND_RECV_VARIADIC_SPEC_HANDLER(ZEND_OPCODE_HANDLER_AR
 
        for (; arg_num <= arg_count; ++arg_num) {
                zval **param = zend_vm_stack_get_arg(arg_num TSRMLS_CC);
-               zend_verify_arg_type((zend_function *) EG(active_op_array), arg_num, *param, opline->extended_value TSRMLS_CC);
+               zend_verify_arg_type((zend_function *) EG(active_op_array), arg_num, *param, NULL, opline->extended_value TSRMLS_CC);
                zend_hash_next_index_insert(Z_ARRVAL_P(params), param, sizeof(zval *), NULL);
                Z_ADDREF_PP(param);
        }
@@ -1615,27 +1615,34 @@ static int ZEND_FASTCALL  ZEND_INIT_NS_FCALL_BY_NAME_SPEC_CONST_HANDLER(ZEND_OPC
 static int ZEND_FASTCALL  ZEND_RECV_INIT_SPEC_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
 {
        USE_OPLINE
-       zval *assignment_value;
+       zval *assignment_value, *default_val = NULL;
        zend_uint arg_num = opline->op1.num;
        zval **param = zend_vm_stack_get_arg(arg_num TSRMLS_CC);
        zval **var_ptr;
 
        SAVE_OPLINE();
+       if (IS_CONSTANT_TYPE(Z_TYPE_P(opline->op2.zv))) {
+               ALLOC_ZVAL(default_val);
+               *default_val = *opline->op2.zv;
+               Z_SET_REFCOUNT_P(default_val, 1);
+               zval_update_constant(&default_val, 0 TSRMLS_CC);
+       }
        if (param == NULL) {
-               ALLOC_ZVAL(assignment_value);
-               *assignment_value = *opline->op2.zv;
-               if (IS_CONSTANT_TYPE(Z_TYPE_P(assignment_value))) {
-                       Z_SET_REFCOUNT_P(assignment_value, 1);
-                       zval_update_constant(&assignment_value, 0 TSRMLS_CC);
-               } else if (Z_TYPE_P(assignment_value) == IS_ARRAY) {
-                       HashTable *ht;
-
-                       ALLOC_HASHTABLE(ht);
-                       zend_hash_init(ht, zend_hash_num_elements(Z_ARRVAL_P(assignment_value)), NULL, ZVAL_PTR_DTOR, 0);
-                       zend_hash_copy(ht, Z_ARRVAL_P(assignment_value), (copy_ctor_func_t) zval_deep_copy, NULL, sizeof(zval *));
-                       Z_ARRVAL_P(assignment_value) = ht;
+               if (default_val) {
+                       assignment_value = default_val;
                } else {
-                       zval_copy_ctor(assignment_value);
+                       ALLOC_ZVAL(assignment_value);
+                       *assignment_value = *opline->op2.zv;
+                       if (Z_TYPE_P(assignment_value) == IS_ARRAY) {
+                               HashTable *ht;
+
+                               ALLOC_HASHTABLE(ht);
+                               zend_hash_init(ht, zend_hash_num_elements(Z_ARRVAL_P(assignment_value)), NULL, ZVAL_PTR_DTOR, 0);
+                               zend_hash_copy(ht, Z_ARRVAL_P(assignment_value), (copy_ctor_func_t) zval_deep_copy, NULL, sizeof(zval *));
+                               Z_ARRVAL_P(assignment_value) = ht;
+                       } else {
+                               zval_copy_ctor(assignment_value);
+                       }
                }
                INIT_PZVAL(assignment_value);
        } else {
@@ -1643,11 +1650,16 @@ static int ZEND_FASTCALL  ZEND_RECV_INIT_SPEC_CONST_HANDLER(ZEND_OPCODE_HANDLER_
                Z_ADDREF_P(assignment_value);
        }
 
-       zend_verify_arg_type((zend_function *) EG(active_op_array), arg_num, assignment_value, opline->extended_value TSRMLS_CC);
+       zend_verify_arg_type((zend_function *) EG(active_op_array), arg_num, assignment_value, default_val, opline->extended_value TSRMLS_CC);
        var_ptr = _get_zval_ptr_ptr_cv_BP_VAR_W(execute_data, opline->result.var TSRMLS_CC);
        zval_ptr_dtor(var_ptr);
        *var_ptr = assignment_value;
 
+       if (default_val && assignment_value != default_val) {
+               zval_dtor(default_val);
+               efree(default_val);
+       }
+
        CHECK_EXCEPTION();
        ZEND_VM_NEXT_OPCODE();
 }