diff options
Diffstat (limited to 'Zend/zend_execute.c')
-rw-r--r-- | Zend/zend_execute.c | 242 |
1 files changed, 77 insertions, 165 deletions
diff --git a/Zend/zend_execute.c b/Zend/zend_execute.c index 3ad663445b..ad788aff44 100644 --- a/Zend/zend_execute.c +++ b/Zend/zend_execute.c @@ -607,25 +607,6 @@ static inline int make_real_object(zval *object) return 1; } -static zend_class_entry *zend_verify_internal_arg_class_kind( - const zend_internal_arg_info *cur_arg_info) -{ - zend_string *key; - zend_class_entry *ce; - ALLOCA_FLAG(use_heap); - - ZSTR_ALLOCA_INIT(key, cur_arg_info->class_name, strlen(cur_arg_info->class_name), use_heap); - ce = zend_fetch_class(key, (ZEND_FETCH_CLASS_AUTO | ZEND_FETCH_CLASS_NO_AUTOLOAD)); - ZSTR_ALLOCA_FREE(key, use_heap); - - return ce; -} - -static zend_always_inline zend_class_entry* zend_verify_arg_class_kind(const zend_arg_info *cur_arg_info) -{ - return zend_fetch_class(cur_arg_info->class_name, (ZEND_FETCH_CLASS_AUTO | ZEND_FETCH_CLASS_NO_AUTOLOAD)); -} - static ZEND_COLD void zend_verify_type_error_common( const zend_function *zf, const zend_arg_info *arg_info, const zend_class_entry *ce, zval *value, @@ -644,46 +625,46 @@ static ZEND_COLD void zend_verify_type_error_common( *fclass = ""; } - switch (arg_info->type_hint) { - case IS_OBJECT: - if (ce) { - if (ce->ce_flags & ZEND_ACC_INTERFACE) { - *need_msg = "implement interface "; - is_interface = 1; - } else { - *need_msg = "be an instance of "; - } - *need_kind = ZSTR_VAL(ce->name); + if (ZEND_TYPE_IS_CLASS(arg_info->type)) { + if (ce) { + if (ce->ce_flags & ZEND_ACC_INTERFACE) { + *need_msg = "implement interface "; + is_interface = 1; } else { - /* We don't know whether it's a class or interface, assume it's a class */ *need_msg = "be an instance of "; - *need_kind = zf->common.type == ZEND_INTERNAL_FUNCTION - ? ((zend_internal_arg_info *) arg_info)->class_name - : ZSTR_VAL(arg_info->class_name); } - break; - case IS_CALLABLE: - *need_msg = "be callable"; - *need_kind = ""; - break; - case IS_ITERABLE: - *need_msg = "be iterable"; - *need_kind = ""; - break; - default: - *need_msg = "be of the type "; - *need_kind = zend_get_type_by_const(arg_info->type_hint); - break; + *need_kind = ZSTR_VAL(ce->name); + } else { + /* We don't know whether it's a class or interface, assume it's a class */ + + *need_msg = "be an instance of "; + *need_kind = ZSTR_VAL(ZEND_TYPE_NAME(arg_info->type)); + } + } else { + switch (ZEND_TYPE_CODE(arg_info->type)) { + case IS_CALLABLE: + *need_msg = "be callable"; + *need_kind = ""; + break; + case IS_ITERABLE: + *need_msg = "be iterable"; + *need_kind = ""; + break; + default: + *need_msg = "be of the type "; + *need_kind = zend_get_type_by_const(ZEND_TYPE_CODE(arg_info->type)); + break; + } } - if (arg_info->allow_null) { + if (ZEND_TYPE_ALLOW_NULL(arg_info->type)) { *need_or_null = is_interface ? " or be null" : " or null"; } else { *need_or_null = ""; } if (value) { - if (arg_info->type_hint == IS_OBJECT && Z_TYPE_P(value) == IS_OBJECT) { + if (ZEND_TYPE_IS_CLASS(arg_info->type) && Z_TYPE_P(value) == IS_OBJECT) { *given_msg = "instance of "; *given_kind = ZSTR_VAL(Z_OBJCE_P(value)->name); } else { @@ -803,137 +784,48 @@ static zend_bool zend_verify_scalar_type_hint(zend_uchar type_hint, zval *arg, z return zend_verify_weak_scalar_type_hint(type_hint, arg); } -static zend_always_inline zend_bool zend_check_internal_type( - const zend_function *zf, const zend_internal_arg_info *arg_info, - zval *arg, zend_class_entry **ce, zend_bool is_return_type) -{ - if (!arg_info->type_hint) { - return 1; - } - - ZVAL_DEREF(arg); - if (EXPECTED(arg_info->type_hint == Z_TYPE_P(arg))) { - if (arg_info->class_name) { - *ce = zend_verify_internal_arg_class_kind(arg_info); - return *ce && instanceof_function(Z_OBJCE_P(arg), *ce); - } - return 1; - } - - if (Z_TYPE_P(arg) == IS_NULL && arg_info->allow_null) { - return 1; - } - - if (arg_info->class_name) { - *ce = zend_verify_internal_arg_class_kind(arg_info); - return 0; - } else if (arg_info->type_hint == IS_CALLABLE) { - return zend_is_callable(arg, IS_CALLABLE_CHECK_SILENT, NULL); - } else if (arg_info->type_hint == IS_ITERABLE) { - return zend_is_iterable(arg); - } else if (arg_info->type_hint == _IS_BOOL && - EXPECTED(Z_TYPE_P(arg) == IS_FALSE || Z_TYPE_P(arg) == IS_TRUE)) { - return 1; - } else if (is_return_type) { - /* Internal return types are always strict */ - return 0; - } else { - /* Internal parameter types honor strict_types */ - return zend_verify_scalar_type_hint(arg_info->type_hint, arg, ZEND_CALL_USES_STRICT_TYPES(EG(current_execute_data))); - } -} - -static int zend_verify_internal_arg_type(zend_function *zf, uint32_t arg_num, zval *arg) -{ - const zend_internal_arg_info *cur_arg_info; - zend_class_entry *ce = NULL; - - if (EXPECTED(arg_num <= zf->internal_function.num_args)) { - cur_arg_info = &zf->internal_function.arg_info[arg_num-1]; - } else if (zf->internal_function.fn_flags & ZEND_ACC_VARIADIC) { - cur_arg_info = &zf->internal_function.arg_info[zf->internal_function.num_args]; - } else { - return 1; - } - - if (UNEXPECTED(!zend_check_internal_type(zf, cur_arg_info, arg, &ce, 0))) { - zend_verify_arg_error(zf, (const zend_arg_info *) cur_arg_info, arg_num, ce, arg); - return 0; - } - - return 1; -} - -static zend_never_inline int zend_verify_internal_arg_types(zend_function *fbc, zend_execute_data *call) -{ - uint32_t i; - uint32_t num_args = ZEND_CALL_NUM_ARGS(call); - zval *p = ZEND_CALL_ARG(call, 1); - - for (i = 0; i < num_args; ++i) { - if (UNEXPECTED(!zend_verify_internal_arg_type(fbc, i + 1, p))) { - EG(current_execute_data) = call->prev_execute_data; - zend_vm_stack_free_args(call); - return 0; - } - p++; - } - return 1; -} - static zend_always_inline zend_bool zend_check_type( - const zend_function *zf, const zend_arg_info *arg_info, + zend_type type, zval *arg, zend_class_entry **ce, void **cache_slot, - zval *default_value, zend_bool is_return_type) + zval *default_value, zend_class_entry *scope, + zend_bool is_return_type) { - if (!arg_info->type_hint) { + if (!ZEND_TYPE_IS_SET(type)) { return 1; } ZVAL_DEREF(arg); - if (EXPECTED(arg_info->type_hint == Z_TYPE_P(arg))) { - if (arg_info->class_name) { - if (EXPECTED(*cache_slot)) { - *ce = (zend_class_entry *) *cache_slot; - } else { - *ce = zend_verify_arg_class_kind(arg_info); - if (UNEXPECTED(!*ce)) { - return 0; - } - *cache_slot = (void *) *ce; - } - if (UNEXPECTED(!instanceof_function(Z_OBJCE_P(arg), *ce))) { + if (ZEND_TYPE_IS_CLASS(type)) { + if (EXPECTED(*cache_slot)) { + *ce = (zend_class_entry *) *cache_slot; + } else { + *ce = zend_fetch_class(ZEND_TYPE_NAME(type), (ZEND_FETCH_CLASS_AUTO | ZEND_FETCH_CLASS_NO_AUTOLOAD)); + if (UNEXPECTED(!*ce)) { return 0; } + *cache_slot = (void *) *ce; + } + if (EXPECTED(Z_TYPE_P(arg) == IS_OBJECT)) { + return instanceof_function(Z_OBJCE_P(arg), *ce); } + } else if (EXPECTED(ZEND_TYPE_CODE(type) == Z_TYPE_P(arg))) { return 1; } - if (Z_TYPE_P(arg) == IS_NULL && (arg_info->allow_null || (default_value && is_null_constant(zf->common.scope, default_value)))) { + if (Z_TYPE_P(arg) == IS_NULL && (ZEND_TYPE_ALLOW_NULL(type) || (default_value && is_null_constant(scope, default_value)))) { /* Null passed to nullable type */ return 1; } - if (UNEXPECTED(arg_info->class_name)) { - /* This is always an error - we fetch the class name for the error message here */ - if (EXPECTED(*cache_slot)) { - *ce = (zend_class_entry *) *cache_slot; - } else { - *ce = zend_verify_arg_class_kind(arg_info); - if (*ce) { - *cache_slot = (void *) *ce; - } - } - return 0; - } else if (arg_info->type_hint == IS_CALLABLE) { + if (ZEND_TYPE_CODE(type) == IS_CALLABLE) { return zend_is_callable(arg, IS_CALLABLE_CHECK_SILENT, NULL); - } else if (arg_info->type_hint == IS_ITERABLE) { + } else if (ZEND_TYPE_CODE(type) == IS_ITERABLE) { return zend_is_iterable(arg); - } else if (arg_info->type_hint == _IS_BOOL && + } else if (ZEND_TYPE_CODE(type) == _IS_BOOL && EXPECTED(Z_TYPE_P(arg) == IS_FALSE || Z_TYPE_P(arg) == IS_TRUE)) { return 1; } else { - return zend_verify_scalar_type_hint(arg_info->type_hint, arg, + return zend_verify_scalar_type_hint(ZEND_TYPE_CODE(type), arg, is_return_type ? ZEND_RET_USES_STRICT_TYPES() : ZEND_ARG_USES_STRICT_TYPES()); } @@ -954,7 +846,7 @@ static zend_always_inline int zend_verify_arg_type(zend_function *zf, uint32_t a return 1; } - if (UNEXPECTED(!zend_check_type(zf, cur_arg_info, arg, &ce, cache_slot, default_value, 0))) { + if (UNEXPECTED(!zend_check_type(cur_arg_info->type, arg, &ce, cache_slot, default_value, zf->common.scope, 0))) { zend_verify_arg_error(zf, cur_arg_info, arg_num, ce, arg); return 0; } @@ -962,6 +854,25 @@ static zend_always_inline int zend_verify_arg_type(zend_function *zf, uint32_t a return 1; } +static zend_never_inline int zend_verify_internal_arg_types(zend_function *fbc, zend_execute_data *call) +{ + uint32_t i; + uint32_t num_args = ZEND_CALL_NUM_ARGS(call); + zval *p = ZEND_CALL_ARG(call, 1); + void *dummy_cache_slot; + + for (i = 0; i < num_args; ++i) { + dummy_cache_slot = NULL; + if (UNEXPECTED(!zend_verify_arg_type(fbc, i + 1, p, NULL, &dummy_cache_slot))) { + EG(current_execute_data) = call->prev_execute_data; + zend_vm_stack_free_args(call); + return 0; + } + p++; + } + return 1; +} + ZEND_API ZEND_COLD void ZEND_FASTCALL zend_missing_arg_error(zend_execute_data *execute_data) { zend_execute_data *ptr = EX(prev_execute_data); @@ -1040,13 +951,14 @@ static int zend_verify_internal_return_type(zend_function *zf, zval *ret) { zend_internal_arg_info *ret_info = zf->internal_function.arg_info - 1; zend_class_entry *ce = NULL; + void *dummy_cache_slot = NULL; - if (UNEXPECTED(ret_info->type_hint == IS_VOID && Z_TYPE_P(ret) != IS_NULL)) { + if (UNEXPECTED(ZEND_TYPE_CODE(ret_info->type) == IS_VOID && Z_TYPE_P(ret) != IS_NULL)) { zend_verify_void_return_error(zf, zend_zval_type_name(ret), ""); return 0; } - if (UNEXPECTED(!zend_check_internal_type(zf, ret_info, ret, &ce, 1))) { + if (UNEXPECTED(!zend_check_type(ret_info->type, ret, &ce, &dummy_cache_slot, NULL, NULL, 1))) { zend_verify_internal_return_error(zf, ce, ret); return 0; } @@ -1060,7 +972,7 @@ static zend_always_inline void zend_verify_return_type(zend_function *zf, zval * zend_arg_info *ret_info = zf->common.arg_info - 1; zend_class_entry *ce = NULL; - if (UNEXPECTED(!zend_check_type(zf, ret_info, ret, &ce, cache_slot, NULL, 1))) { + if (UNEXPECTED(!zend_check_type(ret_info->type, ret, &ce, cache_slot, NULL, NULL, 1))) { zend_verify_return_error(zf, ce, ret); } } @@ -1069,13 +981,13 @@ static ZEND_COLD int zend_verify_missing_return_type(zend_function *zf, void **c { zend_arg_info *ret_info = zf->common.arg_info - 1; - if (ret_info->type_hint && UNEXPECTED(ret_info->type_hint != IS_VOID)) { + if (ZEND_TYPE_IS_SET(ret_info->type) && UNEXPECTED(ZEND_TYPE_CODE(ret_info->type) != IS_VOID)) { zend_class_entry *ce = NULL; - if (ret_info->class_name) { + if (ZEND_TYPE_IS_CLASS(ret_info->type)) { if (EXPECTED(*cache_slot)) { ce = (zend_class_entry*) *cache_slot; } else { - ce = zend_verify_arg_class_kind(ret_info); + ce = zend_fetch_class(ZEND_TYPE_NAME(ret_info->type), (ZEND_FETCH_CLASS_AUTO | ZEND_FETCH_CLASS_NO_AUTOLOAD)); if (ce) { *cache_slot = (void*)ce; } @@ -3072,7 +2984,7 @@ ZEND_API zval *zend_get_zval_ptr(int op_type, const znode_op *node, const zend_e ZEND_API void ZEND_FASTCALL zend_check_internal_arg_type(zend_function *zf, uint32_t arg_num, zval *arg) { - zend_verify_internal_arg_type(zf, arg_num, arg); + zend_verify_arg_type(zf, arg_num, arg, NULL, NULL); } ZEND_API int ZEND_FASTCALL zend_check_arg_type(zend_function *zf, uint32_t arg_num, zval *arg, zval *default_value, void **cache_slot) |