summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Zend/zend_compile.c14
-rw-r--r--Zend/zend_execute.c18
-rw-r--r--Zend/zend_vm_def.h25
-rw-r--r--Zend/zend_vm_execute.h25
4 files changed, 57 insertions, 25 deletions
diff --git a/Zend/zend_compile.c b/Zend/zend_compile.c
index d15b85fc0b..ee3aa75ad1 100644
--- a/Zend/zend_compile.c
+++ b/Zend/zend_compile.c
@@ -3831,11 +3831,15 @@ void zend_compile_params(zend_ast *ast TSRMLS_DC) /* {{{ */
arg_info->class_name_len = 0;
if (type_ast) {
- zend_bool has_null_default = default_ast
- && (Z_TYPE(default_node.u.constant) == IS_NULL
- || (Z_TYPE(default_node.u.constant) == IS_CONSTANT
- && strcasecmp(Z_STRVAL(default_node.u.constant), "NULL") == 0)
- || Z_TYPE(default_node.u.constant) == IS_CONSTANT_AST); // ???
+ zend_bool has_null_default = 0;
+
+ if (default_ast) {
+ if (!(has_null_default = (Z_TYPE(default_node.u.constant) == IS_NULL || (Z_TYPE(default_node.u.constant) == IS_CONSTANT && strcasecmp(Z_STRVAL(default_node.u.constant), "NULL") == 0)))) {
+ if (Z_OPT_CONSTANT(default_node.u.constant)) {
+ has_null_default = 2;
+ }
+ }
+ }
op_array->fn_flags |= ZEND_ACC_HAS_TYPE_HINTS;
arg_info->allow_null = has_null_default;
diff --git a/Zend/zend_execute.c b/Zend/zend_execute.c
index 4fcd1de6b8..00e72a0e61 100644
--- a/Zend/zend_execute.c
+++ b/Zend/zend_execute.c
@@ -574,7 +574,17 @@ ZEND_API void zend_verify_arg_error(int error_type, const zend_function *zf, uin
}
}
-static void zend_verify_arg_type(zend_function *zf, uint32_t arg_num, zval *arg 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 void zend_verify_arg_type(zend_function *zf, uint32_t arg_num, zval *arg, zval *defaultval TSRMLS_DC)
{
zend_arg_info *cur_arg_info;
char *need_msg;
@@ -601,18 +611,18 @@ static void zend_verify_arg_type(zend_function *zf, uint32_t arg_num, zval *arg
if (!ce || !instanceof_function(Z_OBJCE_P(arg), ce TSRMLS_CC)) {
zend_verify_arg_error(E_RECOVERABLE_ERROR, zf, arg_num, need_msg, class_name, "instance of ", Z_OBJCE_P(arg)->name->val, arg 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, &class_name, &ce TSRMLS_CC);
zend_verify_arg_error(E_RECOVERABLE_ERROR, zf, arg_num, need_msg, class_name, zend_zval_type_name(arg), "", arg TSRMLS_CC);
}
} else if (cur_arg_info->type_hint) {
if (cur_arg_info->type_hint == IS_ARRAY) {
ZVAL_DEREF(arg);
- 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))) {
zend_verify_arg_error(E_RECOVERABLE_ERROR, zf, arg_num, "be of the type array", "", zend_zval_type_name(arg), "", arg TSRMLS_CC);
}
} else if (cur_arg_info->type_hint == IS_CALLABLE) {
- 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))) {
zend_verify_arg_error(E_RECOVERABLE_ERROR, zf, arg_num, "be callable", "", zend_zval_type_name(arg), "", arg TSRMLS_CC);
}
#if ZEND_DEBUG
diff --git a/Zend/zend_vm_def.h b/Zend/zend_vm_def.h
index eb181d9c27..78ef315ec7 100644
--- a/Zend/zend_vm_def.h
+++ b/Zend/zend_vm_def.h
@@ -2675,7 +2675,7 @@ ZEND_VM_HANDLER(60, ZEND_DO_FCALL, ANY, ANY)
zval *p = ZEND_CALL_ARG(call, 1);
for (i = 0; i < call->num_args; ++i) {
- zend_verify_arg_type(fbc, i + 1, p TSRMLS_CC);
+ zend_verify_arg_type(fbc, i + 1, p, NULL TSRMLS_CC);
p++;
}
if (UNEXPECTED(EG(exception) != NULL)) {
@@ -3528,7 +3528,7 @@ ZEND_VM_HANDLER(63, ZEND_RECV, ANY, ANY)
} else if (UNEXPECTED((EX(func)->op_array.fn_flags & ZEND_ACC_HAS_TYPE_HINTS) != 0)) {
zval *param = _get_zval_ptr_cv_undef_BP_VAR_W(execute_data, opline->result.var TSRMLS_CC);
- zend_verify_arg_type(EX(func), arg_num, param TSRMLS_CC);
+ zend_verify_arg_type(EX(func), arg_num, param, NULL TSRMLS_CC);
CHECK_EXCEPTION();
}
@@ -3539,15 +3539,20 @@ ZEND_VM_HANDLER(64, ZEND_RECV_INIT, ANY, CONST)
{
USE_OPLINE
uint32_t arg_num = opline->op1.num;
- zval *param;
+ zval *param, default_val = {{0}};
SAVE_OPLINE();
+ if (Z_OPT_CONSTANT_P(opline->op2.zv)) {
+ ZVAL_COPY_VALUE(&default_val, opline->op2.zv);
+ zval_update_constant(&default_val, 0 TSRMLS_CC);
+ }
+
param = _get_zval_ptr_cv_undef_BP_VAR_W(execute_data, opline->result.var TSRMLS_CC);
if (arg_num > EX(num_args)) {
- ZVAL_COPY_VALUE(param, opline->op2.zv);
- if (Z_OPT_CONSTANT_P(param)) {
- zval_update_constant(param, 0 TSRMLS_CC);
+ if (Z_TYPE(default_val) != IS_UNDEF) {
+ *param = default_val;
} else {
+ ZVAL_COPY_VALUE(param, opline->op2.zv);
/* IS_CONST can't be IS_OBJECT, IS_RESOURCE or IS_REFERENCE */
if (UNEXPECTED(Z_OPT_COPYABLE_P(param))) {
zval_copy_ctor_func(param);
@@ -3556,7 +3561,11 @@ ZEND_VM_HANDLER(64, ZEND_RECV_INIT, ANY, CONST)
}
if (UNEXPECTED((EX(func)->op_array.fn_flags & ZEND_ACC_HAS_TYPE_HINTS) != 0)) {
- zend_verify_arg_type(EX(func), arg_num, param TSRMLS_CC);
+ zend_verify_arg_type(EX(func), arg_num, param, Z_TYPE(default_val) == IS_UNDEF ? NULL : &default_val TSRMLS_CC);
+ }
+
+ if (Z_TYPE(default_val) != IS_UNDEF && arg_num <= EX(num_args)) {
+ zval_dtor(&default_val);
}
CHECK_EXCEPTION();
@@ -3581,7 +3590,7 @@ ZEND_VM_HANDLER(164, ZEND_RECV_VARIADIC, ANY, ANY)
param = EX_VAR_NUM(EX(func)->op_array.last_var + EX(func)->op_array.T);
if (UNEXPECTED((EX(func)->op_array.fn_flags & ZEND_ACC_HAS_TYPE_HINTS) != 0)) {
do {
- zend_verify_arg_type(EX(func), arg_num, param TSRMLS_CC);
+ zend_verify_arg_type(EX(func), arg_num, param, NULL TSRMLS_CC);
zend_hash_next_index_insert_new(Z_ARRVAL_P(params), param);
if (Z_REFCOUNTED_P(param)) Z_ADDREF_P(param);
param++;
diff --git a/Zend/zend_vm_execute.h b/Zend/zend_vm_execute.h
index 2a8e901c57..074dbc2965 100644
--- a/Zend/zend_vm_execute.h
+++ b/Zend/zend_vm_execute.h
@@ -538,7 +538,7 @@ static int ZEND_FASTCALL ZEND_DO_FCALL_SPEC_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
zval *p = ZEND_CALL_ARG(call, 1);
for (i = 0; i < call->num_args; ++i) {
- zend_verify_arg_type(fbc, i + 1, p TSRMLS_CC);
+ zend_verify_arg_type(fbc, i + 1, p, NULL TSRMLS_CC);
p++;
}
if (UNEXPECTED(EG(exception) != NULL)) {
@@ -978,7 +978,7 @@ static int ZEND_FASTCALL ZEND_RECV_SPEC_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
} else if (UNEXPECTED((EX(func)->op_array.fn_flags & ZEND_ACC_HAS_TYPE_HINTS) != 0)) {
zval *param = _get_zval_ptr_cv_undef_BP_VAR_W(execute_data, opline->result.var TSRMLS_CC);
- zend_verify_arg_type(EX(func), arg_num, param TSRMLS_CC);
+ zend_verify_arg_type(EX(func), arg_num, param, NULL TSRMLS_CC);
CHECK_EXCEPTION();
}
@@ -1003,7 +1003,7 @@ static int ZEND_FASTCALL ZEND_RECV_VARIADIC_SPEC_HANDLER(ZEND_OPCODE_HANDLER_AR
param = EX_VAR_NUM(EX(func)->op_array.last_var + EX(func)->op_array.T);
if (UNEXPECTED((EX(func)->op_array.fn_flags & ZEND_ACC_HAS_TYPE_HINTS) != 0)) {
do {
- zend_verify_arg_type(EX(func), arg_num, param TSRMLS_CC);
+ zend_verify_arg_type(EX(func), arg_num, param, NULL TSRMLS_CC);
zend_hash_next_index_insert_new(Z_ARRVAL_P(params), param);
if (Z_REFCOUNTED_P(param)) Z_ADDREF_P(param);
param++;
@@ -1645,15 +1645,20 @@ static int ZEND_FASTCALL ZEND_RECV_INIT_SPEC_CONST_HANDLER(ZEND_OPCODE_HANDLER_
{
USE_OPLINE
uint32_t arg_num = opline->op1.num;
- zval *param;
+ zval *param, default_val = {{0}};
SAVE_OPLINE();
+ if (Z_OPT_CONSTANT_P(opline->op2.zv)) {
+ ZVAL_COPY_VALUE(&default_val, opline->op2.zv);
+ zval_update_constant(&default_val, 0 TSRMLS_CC);
+ }
+
param = _get_zval_ptr_cv_undef_BP_VAR_W(execute_data, opline->result.var TSRMLS_CC);
if (arg_num > EX(num_args)) {
- ZVAL_COPY_VALUE(param, opline->op2.zv);
- if (Z_OPT_CONSTANT_P(param)) {
- zval_update_constant(param, 0 TSRMLS_CC);
+ if (Z_TYPE(default_val) != IS_UNDEF) {
+ *param = default_val;
} else {
+ ZVAL_COPY_VALUE(param, opline->op2.zv);
/* IS_CONST can't be IS_OBJECT, IS_RESOURCE or IS_REFERENCE */
if (UNEXPECTED(Z_OPT_COPYABLE_P(param))) {
zval_copy_ctor_func(param);
@@ -1662,7 +1667,11 @@ static int ZEND_FASTCALL ZEND_RECV_INIT_SPEC_CONST_HANDLER(ZEND_OPCODE_HANDLER_
}
if (UNEXPECTED((EX(func)->op_array.fn_flags & ZEND_ACC_HAS_TYPE_HINTS) != 0)) {
- zend_verify_arg_type(EX(func), arg_num, param TSRMLS_CC);
+ zend_verify_arg_type(EX(func), arg_num, param, Z_TYPE(default_val) == IS_UNDEF ? NULL : &default_val TSRMLS_CC);
+ }
+
+ if (Z_TYPE(default_val) != IS_UNDEF && arg_num <= EX(num_args)) {
+ zval_dtor(&default_val);
}
CHECK_EXCEPTION();