Better fix for bug #68446
authorDmitry Stogov <dmitry@zend.com>
Tue, 25 Nov 2014 15:09:08 +0000 (18:09 +0300)
committerDmitry Stogov <dmitry@zend.com>
Tue, 25 Nov 2014 15:09:08 +0000 (18:09 +0300)
Zend/zend_compile.c
Zend/zend_execute.c
Zend/zend_vm_def.h
Zend/zend_vm_execute.h

index 8e416ea0a596adf74d43de0674087ddb5afbbe35..ccaf1652c256a850f53a03d90b1afd463ac93daf 100644 (file)
@@ -1931,8 +1931,11 @@ 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) {
+                                       if (Z_TYPE(initialization->u.constant) == IS_NULL || (Z_TYPE(initialization->u.constant) == IS_CONSTANT && !strcasecmp(Z_STRVAL(initialization->u.constant), "NULL"))) {
                                                cur_arg_info->allow_null = 1;
+                                       } else if (IS_CONSTANT_TYPE(Z_TYPE(initialization->u.constant))) {
+                                               /* delay constant resolution and check to run-time */
+                                               cur_arg_info->allow_null = 0;
                                        } 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 +1943,11 @@ 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) {
+                                       if (Z_TYPE(initialization->u.constant) == IS_NULL || (Z_TYPE(initialization->u.constant) == IS_CONSTANT && !strcasecmp(Z_STRVAL(initialization->u.constant), "NULL"))) {
                                                cur_arg_info->allow_null = 1;
+                                       } else if (IS_CONSTANT_TYPE(Z_TYPE(initialization->u.constant))) {
+                                               /* delay constant resolution and check to run-time */
+                                               cur_arg_info->allow_null = 0;
                                        } else {
                                                zend_error_noreturn(E_COMPILE_ERROR, "Default value for parameters with callable type hint can only be NULL");
                                        }
@@ -1955,8 +1961,11 @@ void zend_do_receive_param(zend_uchar op, znode *varname, const znode *initializ
                                cur_arg_info->class_name = Z_STRVAL(class_type->u.constant);
                                cur_arg_info->class_name_len = Z_STRLEN(class_type->u.constant);
                                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) {
+                                       if (Z_TYPE(initialization->u.constant) == IS_NULL || (Z_TYPE(initialization->u.constant) == IS_CONSTANT && !strcasecmp(Z_STRVAL(initialization->u.constant), "NULL"))) {
                                                cur_arg_info->allow_null = 1;
+                                       } else if (IS_CONSTANT_TYPE(Z_TYPE(initialization->u.constant))) {
+                                               /* delay constant resolution and check to run-time */
+                                               cur_arg_info->allow_null = 0;
                                        } else {
                                                zend_error_noreturn(E_COMPILE_ERROR, "Default value for parameters with a class type hint can only be NULL");
                                        }
index 6ada04e1cb5c5f4ea15876550e1aff1e5f921a17..7ef6d1c3e6d63d41568bf9ec14ea606fe081d86e 100644 (file)
@@ -608,7 +608,22 @@ 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 int is_null_constant(zval *default_value)
+{
+       if (IS_CONSTANT_TYPE(Z_TYPE_P(default_value))) {
+               zval constant = *default_value;
+               zval *constant_ptr = &constant;
+
+               zval_update_constant(&constant_ptr, 0 TSRMLS_CC);
+               if (Z_TYPE(constant) == IS_NULL) {
+                       return 1;
+               }
+               zval_dtor(&constant);
+       }
+       return 0;
+}
+
+static inline int zend_verify_arg_type(zend_function *zf, zend_uint arg_num, zval *arg, ulong fetch_type, zval *default_value TSRMLS_DC)
 {
        zend_arg_info *cur_arg_info;
        char *need_msg;
@@ -638,7 +653,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 || !(cur_arg_info->allow_null || (default_value && is_null_constant(default_value)))) {
                        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 +664,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 || !(cur_arg_info->allow_null || (default_value && is_null_constant(default_value))))) {
                                        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 +673,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 || !(cur_arg_info->allow_null || (default_value && is_null_constant(default_value))))) {
                                        return zend_verify_arg_error(E_RECOVERABLE_ERROR, zf, arg_num, "be callable", "", zend_zval_type_name(arg), "" TSRMLS_CC);
                                }
                                break;
index 705e46e7d338ea9891a2a520fa584047997c362e..03fa7cf09b756ef213f1c5a23e486e40bc123d0e 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, 0, NULL 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, opline->extended_value, NULL 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, opline->extended_value, NULL 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;
@@ -3438,7 +3438,7 @@ 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, opline->extended_value, opline->op2.zv 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;
@@ -3469,7 +3469,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, opline->extended_value, NULL TSRMLS_CC);
                zend_hash_next_index_insert(Z_ARRVAL_P(params), param, sizeof(zval *), NULL);
                Z_ADDREF_PP(param);
        }
index 993aaee7474e5a61a5700fa3541d0f2821bd8227..20731b4ef5f65116f277781e2c3ac925148ed330 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, 0, NULL 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, opline->extended_value, NULL 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, opline->extended_value, NULL 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, opline->extended_value, NULL TSRMLS_CC);
                zend_hash_next_index_insert(Z_ARRVAL_P(params), param, sizeof(zval *), NULL);
                Z_ADDREF_PP(param);
        }
@@ -1643,7 +1643,7 @@ 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, opline->extended_value, opline->op2.zv 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;