diff --git a/Zend/zend_API.c b/Zend/zend_API.c index 72b3ec5c601..e055a63b8dc 100644 --- a/Zend/zend_API.c +++ b/Zend/zend_API.c @@ -149,12 +149,12 @@ ZEND_API int zend_copy_parameters_array(int param_count, zval *argument_array) / } /* }}} */ -ZEND_API void zend_wrong_param_count(void) /* {{{ */ +ZEND_API void zend_wrong_param_count(zend_bool strict) /* {{{ */ { const char *space; const char *class_name = get_active_class_name(&space); - zend_error(E_WARNING, "Wrong parameter count for %s%s%s()", class_name, space, get_active_function_name()); + zend_error(strict ? E_RECOVERABLE_ERROR : E_WARNING, "Wrong parameter count for %s%s%s()", class_name, space, get_active_function_name()); } /* }}} */ @@ -234,12 +234,12 @@ ZEND_API int parse_arg_object_to_str(zval *arg, zend_string **str, int type) /* /* }}} */ #ifdef FAST_ZPP -ZEND_API void zend_wrong_paramers_count_error(int num_args, int min_num_args, int max_num_args) /* {{{ */ +ZEND_API void zend_wrong_paramers_count_error(int num_args, int min_num_args, int max_num_args, zend_bool strict) /* {{{ */ { zend_function *active_function = EG(current_execute_data)->func; const char *class_name = active_function->common.scope ? active_function->common.scope->name->val : ""; - zend_error(E_WARNING, "%s%s%s() expects %s %d parameter%s, %d given", + zend_error(strict ? E_RECOVERABLE_ERROR : E_WARNING, "%s%s%s() expects %s %d parameter%s, %d given", class_name, \ class_name[0] ? "::" : "", \ active_function->common.function_name->val, @@ -250,7 +250,7 @@ ZEND_API void zend_wrong_paramers_count_error(int num_args, int min_num_args, in } /* }}} */ -ZEND_API void zend_wrong_paramer_type_error(int num, zend_expected_type expected_type, zval *arg) /* {{{ */ +ZEND_API void zend_wrong_paramer_type_error(int num, zend_expected_type expected_type, zval *arg, zend_bool strict) /* {{{ */ { const char *space; const char *class_name = get_active_class_name(&space); @@ -259,17 +259,17 @@ ZEND_API void zend_wrong_paramer_type_error(int num, zend_expected_type expected NULL }; - zend_error(E_WARNING, "%s%s%s() expects parameter %d to be %s, %s given", + zend_error(strict ? E_RECOVERABLE_ERROR : E_WARNING, "%s%s%s() expects parameter %d to be %s, %s given", class_name, space, get_active_function_name(), num, expected_error[expected_type], zend_zval_type_name(arg)); } /* }}} */ -ZEND_API void zend_wrong_paramer_class_error(int num, char *name, zval *arg) /* {{{ */ +ZEND_API void zend_wrong_paramer_class_error(int num, char *name, zval *arg, zend_bool strict) /* {{{ */ { const char *space; const char *class_name = get_active_class_name(&space); - zend_error(E_WARNING, "%s%s%s() expects parameter %d to be %s, %s given", + zend_error(strict ? E_RECOVERABLE_ERROR : E_WARNING, "%s%s%s() expects parameter %d to be %s, %s given", class_name, space, get_active_function_name(), num, name, zend_zval_type_name(arg)); } /* }}} */ @@ -285,7 +285,7 @@ ZEND_API void zend_wrong_callback_error(int severity, int num, char *error) /* { } /* }}} */ -ZEND_API int zend_parse_arg_class(zval *arg, zend_class_entry **pce, int num, int check_null) /* {{{ */ +ZEND_API int zend_parse_arg_class(zval *arg, zend_class_entry **pce, int num, int check_null, zend_bool strict) /* {{{ */ { zend_class_entry *ce_base = *pce; @@ -300,7 +300,7 @@ ZEND_API int zend_parse_arg_class(zval *arg, zend_class_entry **pce, int num, in const char *space; const char *class_name = get_active_class_name(&space); - zend_error(E_WARNING, "%s%s%s() expects parameter %d to be a class name derived from %s, '%s' given", + zend_error(strict ? E_RECOVERABLE_ERROR : E_WARNING, "%s%s%s() expects parameter %d to be a class name derived from %s, '%s' given", class_name, space, get_active_function_name(), num, ce_base->name->val, Z_STRVAL_P(arg)); *pce = NULL; @@ -311,7 +311,7 @@ ZEND_API int zend_parse_arg_class(zval *arg, zend_class_entry **pce, int num, in const char *space; const char *class_name = get_active_class_name(&space); - zend_error(E_WARNING, "%s%s%s() expects parameter %d to be a valid class name, '%s' given", + zend_error(strict ? E_RECOVERABLE_ERROR : E_WARNING, "%s%s%s() expects parameter %d to be a valid class name, '%s' given", class_name, space, get_active_function_name(), num, Z_STRVAL_P(arg)); return 0; @@ -321,7 +321,7 @@ ZEND_API int zend_parse_arg_class(zval *arg, zend_class_entry **pce, int num, in /* }}} */ #endif -static const char *zend_parse_arg_impl(int arg_num, zval *arg, va_list *va, const char **spec, char **error, int *severity) /* {{{ */ +static const char *zend_parse_arg_impl(int arg_num, zval *arg, va_list *va, const char **spec, char **error, int *severity, zend_bool strict) /* {{{ */ { const char *spec_walk = *spec; char c = *spec_walk++; @@ -353,7 +353,7 @@ static const char *zend_parse_arg_impl(int arg_num, zval *arg, va_list *va, cons is_null = va_arg(*va, zend_bool *); } - if (!zend_parse_arg_long(arg, p, is_null, check_null, c == 'L')) { + if (!zend_parse_arg_long(arg, p, is_null, check_null, c == 'L', strict)) { return "integer"; } } @@ -368,7 +368,7 @@ static const char *zend_parse_arg_impl(int arg_num, zval *arg, va_list *va, cons is_null = va_arg(*va, zend_bool *); } - if (!zend_parse_arg_double(arg, p, is_null, check_null)) { + if (!zend_parse_arg_double(arg, p, is_null, check_null, strict)) { return "float"; } } @@ -378,7 +378,7 @@ static const char *zend_parse_arg_impl(int arg_num, zval *arg, va_list *va, cons { char **p = va_arg(*va, char **); size_t *pl = va_arg(*va, size_t *); - if (!zend_parse_arg_string(arg, p, pl, check_null)) { + if (!zend_parse_arg_string(arg, p, pl, check_null, strict)) { return "string"; } } @@ -388,7 +388,7 @@ static const char *zend_parse_arg_impl(int arg_num, zval *arg, va_list *va, cons { char **p = va_arg(*va, char **); size_t *pl = va_arg(*va, size_t *); - if (!zend_parse_arg_path(arg, p, pl, check_null)) { + if (!zend_parse_arg_path(arg, p, pl, check_null, strict)) { return "a valid path"; } } @@ -397,7 +397,7 @@ static const char *zend_parse_arg_impl(int arg_num, zval *arg, va_list *va, cons case 'P': { zend_string **str = va_arg(*va, zend_string **); - if (!zend_parse_arg_path_str(arg, str, check_null)) { + if (!zend_parse_arg_path_str(arg, str, check_null, strict)) { return "a valid path"; } } @@ -406,7 +406,7 @@ static const char *zend_parse_arg_impl(int arg_num, zval *arg, va_list *va, cons case 'S': { zend_string **str = va_arg(*va, zend_string **); - if (!zend_parse_arg_str(arg, str, check_null)) { + if (!zend_parse_arg_str(arg, str, check_null, strict)) { return "string"; } } @@ -421,7 +421,7 @@ static const char *zend_parse_arg_impl(int arg_num, zval *arg, va_list *va, cons is_null = va_arg(*va, zend_bool *); } - if (!zend_parse_arg_bool(arg, p, is_null, check_null)) { + if (!zend_parse_arg_bool(arg, p, is_null, check_null, strict)) { return "boolean"; } } @@ -540,7 +540,7 @@ static const char *zend_parse_arg_impl(int arg_num, zval *arg, va_list *va, cons break; } else { if (is_callable_error) { - *severity = E_WARNING; + *severity = strict ? E_RECOVERABLE_ERROR : E_WARNING; zend_spprintf(error, 0, "to be a valid callback, %s", is_callable_error); efree(is_callable_error); return ""; @@ -571,13 +571,13 @@ static const char *zend_parse_arg_impl(int arg_num, zval *arg, va_list *va, cons } /* }}} */ -static int zend_parse_arg(int arg_num, zval *arg, va_list *va, const char **spec, int quiet) /* {{{ */ +static int zend_parse_arg(int arg_num, zval *arg, va_list *va, const char **spec, int quiet, zend_bool strict) /* {{{ */ { const char *expected_type = NULL; char *error = NULL; - int severity = E_WARNING; + int severity = strict ? E_RECOVERABLE_ERROR : E_WARNING; - expected_type = zend_parse_arg_impl(arg_num, arg, va, spec, &error, &severity); + expected_type = zend_parse_arg_impl(arg_num, arg, va, spec, &error, &severity, strict); if (expected_type) { if (!quiet && (*expected_type || error)) { const char *space; @@ -607,9 +607,10 @@ ZEND_API int zend_parse_parameter(int flags, int arg_num, zval *arg, const char va_list va; int ret; int quiet = flags & ZEND_PARSE_PARAMS_QUIET; + zend_bool strict = (flags & ZEND_PARSE_PARAMS_STRICT) ? 1 : 0; va_start(va, spec); - ret = zend_parse_arg(arg_num, arg, &va, &spec, quiet); + ret = zend_parse_arg(arg_num, arg, &va, &spec, quiet, strict); va_end(va); return ret; @@ -625,6 +626,7 @@ static int zend_parse_va_args(int num_args, const char *type_spec, va_list *va, zval *arg; int arg_count; int quiet = flags & ZEND_PARSE_PARAMS_QUIET; + zend_bool strict = (flags & ZEND_PARSE_PARAMS_STRICT) ? 1 : 0; zend_bool have_varargs = 0; zval **varargs = NULL; int *n_varargs = NULL; @@ -660,7 +662,7 @@ static int zend_parse_va_args(int num_args, const char *type_spec, va_list *va, if (!quiet) { zend_function *active_function = EG(current_execute_data)->func; const char *class_name = active_function->common.scope ? active_function->common.scope->name->val : ""; - zend_error(E_WARNING, "%s%s%s(): only one varargs specifier (* or +) is permitted", + zend_error(strict ? E_RECOVERABLE_ERROR : E_WARNING, "%s%s%s(): only one varargs specifier (* or +) is permitted", class_name, class_name[0] ? "::" : "", active_function->common.function_name->val); @@ -680,7 +682,7 @@ static int zend_parse_va_args(int num_args, const char *type_spec, va_list *va, if (!quiet) { zend_function *active_function = EG(current_execute_data)->func; const char *class_name = active_function->common.scope ? active_function->common.scope->name->val : ""; - zend_error(E_WARNING, "%s%s%s(): bad type specifier while parsing parameters", + zend_error(strict ? E_RECOVERABLE_ERROR : E_WARNING, "%s%s%s(): bad type specifier while parsing parameters", class_name, class_name[0] ? "::" : "", active_function->common.function_name->val); @@ -703,7 +705,7 @@ static int zend_parse_va_args(int num_args, const char *type_spec, va_list *va, if (!quiet) { zend_function *active_function = EG(current_execute_data)->func; const char *class_name = active_function->common.scope ? active_function->common.scope->name->val : ""; - zend_error(E_WARNING, "%s%s%s() expects %s %d parameter%s, %d given", + zend_error(strict ? E_RECOVERABLE_ERROR : E_WARNING, "%s%s%s() expects %s %d parameter%s, %d given", class_name, class_name[0] ? "::" : "", active_function->common.function_name->val, @@ -718,7 +720,7 @@ static int zend_parse_va_args(int num_args, const char *type_spec, va_list *va, arg_count = ZEND_CALL_NUM_ARGS(EG(current_execute_data)); if (num_args > arg_count) { - zend_error(E_WARNING, "%s(): could not obtain parameters for parsing", + zend_error(strict ? E_RECOVERABLE_ERROR : E_WARNING, "%s(): could not obtain parameters for parsing", get_active_function_name()); return FAILURE; } @@ -752,7 +754,7 @@ static int zend_parse_va_args(int num_args, const char *type_spec, va_list *va, arg = ZEND_CALL_ARG(EG(current_execute_data), i + 1); - if (zend_parse_arg(i+1, arg, va, &type_spec, quiet) == FAILURE) { + if (zend_parse_arg(i+1, arg, va, &type_spec, quiet, strict) == FAILURE) { /* clean up varargs array if it was used */ if (varargs && *varargs) { *varargs = NULL; @@ -766,13 +768,13 @@ static int zend_parse_va_args(int num_args, const char *type_spec, va_list *va, } /* }}} */ -#define RETURN_IF_ZERO_ARGS(num_args, type_spec, quiet) { \ +#define RETURN_IF_ZERO_ARGS(num_args, type_spec, flags) { \ int __num_args = (num_args); \ \ - if (0 == (type_spec)[0] && 0 != __num_args && !(quiet)) { \ + if (0 == (type_spec)[0] && 0 != __num_args && !(flags & ZEND_PARSE_PARAMS_QUIET)) { \ const char *__space; \ const char * __class_name = get_active_class_name(&__space); \ - zend_error(E_WARNING, "%s%s%s() expects exactly 0 parameters, %d given", \ + zend_error((flags & ZEND_PARSE_PARAMS_STRICT) ? E_RECOVERABLE_ERROR : E_WARNING, "%s%s%s() expects exactly 0 parameters, %d given", \ __class_name, __space, \ get_active_function_name(), __num_args); \ return FAILURE; \ @@ -784,7 +786,11 @@ ZEND_API int zend_parse_parameters_ex(int flags, int num_args, const char *type_ va_list va; int retval; - RETURN_IF_ZERO_ARGS(num_args, type_spec, flags & ZEND_PARSE_PARAMS_QUIET); + if (ZEND_CALL_INFO(EG(current_execute_data)) & ZEND_CALL_STRICT_TYPEHINTS) { + flags |= ZEND_PARSE_PARAMS_STRICT; + } + + RETURN_IF_ZERO_ARGS(num_args, type_spec, flags); va_start(va, type_spec); retval = zend_parse_va_args(num_args, type_spec, &va, flags); @@ -798,11 +804,16 @@ ZEND_API int zend_parse_parameters(int num_args, const char *type_spec, ...) /* { va_list va; int retval; + int flags = 0; - RETURN_IF_ZERO_ARGS(num_args, type_spec, 0); + if (ZEND_CALL_INFO(EG(current_execute_data)) & ZEND_CALL_STRICT_TYPEHINTS) { + flags |= ZEND_PARSE_PARAMS_STRICT; + } + + RETURN_IF_ZERO_ARGS(num_args, type_spec, flags); va_start(va, type_spec); - retval = zend_parse_va_args(num_args, type_spec, &va, 0); + retval = zend_parse_va_args(num_args, type_spec, &va, flags); va_end(va); return retval; @@ -813,24 +824,29 @@ ZEND_API int zend_parse_method_parameters(int num_args, zval *this_ptr, const ch { va_list va; int retval; + int flags = 0; const char *p = type_spec; zval **object; zend_class_entry *ce; + if (ZEND_CALL_INFO(EG(current_execute_data)) & ZEND_CALL_STRICT_TYPEHINTS) { + flags |= ZEND_PARSE_PARAMS_STRICT; + } + /* Just checking this_ptr is not enough, because fcall_common_helper does not set * Z_OBJ(EG(This)) to NULL when calling an internal function with common.scope == NULL. * In that case EG(This) would still be the $this from the calling code and we'd take the * wrong branch here. */ zend_bool is_method = EG(current_execute_data)->func->common.scope != NULL; if (!is_method || !this_ptr || Z_TYPE_P(this_ptr) != IS_OBJECT) { - RETURN_IF_ZERO_ARGS(num_args, p, 0); + RETURN_IF_ZERO_ARGS(num_args, p, flags); va_start(va, type_spec); - retval = zend_parse_va_args(num_args, type_spec, &va, 0); + retval = zend_parse_va_args(num_args, type_spec, &va, flags); va_end(va); } else { p++; - RETURN_IF_ZERO_ARGS(num_args, p, 0); + RETURN_IF_ZERO_ARGS(num_args, p, flags); va_start(va, type_spec); @@ -843,7 +859,7 @@ ZEND_API int zend_parse_method_parameters(int num_args, zval *this_ptr, const ch Z_OBJCE_P(this_ptr)->name->val, get_active_function_name(), ce->name->val, get_active_function_name()); } - retval = zend_parse_va_args(num_args, p, &va, 0); + retval = zend_parse_va_args(num_args, p, &va, flags); va_end(va); } return retval; @@ -857,17 +873,20 @@ ZEND_API int zend_parse_method_parameters_ex(int flags, int num_args, zval *this const char *p = type_spec; zval **object; zend_class_entry *ce; - int quiet = flags & ZEND_PARSE_PARAMS_QUIET; + + if (ZEND_CALL_INFO(EG(current_execute_data)) & ZEND_CALL_STRICT_TYPEHINTS) { + flags |= ZEND_PARSE_PARAMS_STRICT; + } if (!this_ptr) { - RETURN_IF_ZERO_ARGS(num_args, p, quiet); + RETURN_IF_ZERO_ARGS(num_args, p, flags); va_start(va, type_spec); retval = zend_parse_va_args(num_args, type_spec, &va, flags); va_end(va); } else { p++; - RETURN_IF_ZERO_ARGS(num_args, p, quiet); + RETURN_IF_ZERO_ARGS(num_args, p, flags); va_start(va, type_spec); @@ -876,7 +895,7 @@ ZEND_API int zend_parse_method_parameters_ex(int flags, int num_args, zval *this *object = this_ptr; if (ce && !instanceof_function(Z_OBJCE_P(this_ptr), ce)) { - if (!quiet) { + if (!(flags & ZEND_PARSE_PARAMS_QUIET)) { zend_error(E_CORE_ERROR, "%s::%s() must be derived from %s::%s", ce->name->val, get_active_function_name(), Z_OBJCE_P(this_ptr)->name->val, get_active_function_name()); } diff --git a/Zend/zend_API.h b/Zend/zend_API.h index d84fbcb2bfe..f0270d0847c 100644 --- a/Zend/zend_API.h +++ b/Zend/zend_API.h @@ -255,7 +255,9 @@ ZEND_API int zend_copy_parameters_array(int param_count, zval *argument_array); /* Parameter parsing API -- andrei */ -#define ZEND_PARSE_PARAMS_QUIET (1<<1) +#define ZEND_PARSE_PARAMS_QUIET (1<<1) +#define ZEND_PARSE_PARAMS_STRICT (1<<2) + ZEND_API int zend_parse_parameters(int num_args, const char *type_spec, ...); ZEND_API int zend_parse_parameters_ex(int flags, int num_args, const char *type_spec, ...); ZEND_API char *zend_zval_type_name(const zval *arg); @@ -293,7 +295,7 @@ ZEND_API int zend_register_class_alias_ex(const char *name, size_t name_len, zen ZEND_API int zend_disable_function(char *function_name, size_t function_name_length); ZEND_API int zend_disable_class(char *class_name, size_t class_name_length); -ZEND_API void zend_wrong_param_count(void); +ZEND_API void zend_wrong_param_count(zend_bool strict); #define IS_CALLABLE_CHECK_SYNTAX_ONLY (1<<0) #define IS_CALLABLE_CHECK_NO_ACCESS (1<<1) @@ -351,12 +353,12 @@ ZEND_API char *zend_get_type_by_const(int type); #define getThis() (Z_OBJ(EX(This)) ? &EX(This) : NULL) #define ZEND_IS_METHOD_CALL() (EX(func)->common.scope != NULL) -#define WRONG_PARAM_COUNT ZEND_WRONG_PARAM_COUNT() -#define WRONG_PARAM_COUNT_WITH_RETVAL(ret) ZEND_WRONG_PARAM_COUNT_WITH_RETVAL(ret) +#define WRONG_PARAM_COUNT ZEND_WRONG_PARAM_COUNT((ZEND_CALL_INFO(EG(current_execute_data)) & ZEND_CALL_STRICT_TYPEHINTS) ? 1 : 0) +#define WRONG_PARAM_COUNT_WITH_RETVAL(ret) ZEND_WRONG_PARAM_COUNT_WITH_RETVAL((ZEND_CALL_INFO(EG(current_execute_data)) & ZEND_CALL_STRICT_TYPEHINTS) ? 1 : 0, ret) #define ARG_COUNT(dummy) EX_NUM_ARGS() #define ZEND_NUM_ARGS() EX_NUM_ARGS() -#define ZEND_WRONG_PARAM_COUNT() { zend_wrong_param_count(); return; } -#define ZEND_WRONG_PARAM_COUNT_WITH_RETVAL(ret) { zend_wrong_param_count(); return ret; } +#define ZEND_WRONG_PARAM_COUNT(strict) { zend_wrong_param_count(strict); return; } +#define ZEND_WRONG_PARAM_COUNT_WITH_RETVAL(strict, ret) { zend_wrong_param_count(strict); return ret; } #ifndef ZEND_WIN32 #define DLEXPORT @@ -701,9 +703,9 @@ typedef enum _zend_expected_type { Z_EXPECTED_LAST } zend_expected_type; -ZEND_API void zend_wrong_paramers_count_error(int num_args, int min_num_args, int max_num_args); -ZEND_API void zend_wrong_paramer_type_error(int num, zend_expected_type expected_type, zval *arg); -ZEND_API void zend_wrong_paramer_class_error(int num, char *name, zval *arg); +ZEND_API void zend_wrong_paramers_count_error(int num_args, int min_num_args, int max_num_args, zend_bool strict); +ZEND_API void zend_wrong_paramer_type_error(int num, zend_expected_type expected_type, zval *arg, zend_bool strict); +ZEND_API void zend_wrong_paramer_class_error(int num, char *name, zval *arg, zend_bool strict); ZEND_API void zend_wrong_callback_error(int severity, int num, char *error); #define ZPP_ERROR_OK 0 @@ -714,7 +716,8 @@ ZEND_API void zend_wrong_callback_error(int severity, int num, char *error); #define ZPP_ERROR_WRONG_COUNT 5 #define ZEND_PARSE_PARAMETERS_START_EX(flags, min_num_args, max_num_args) do { \ - const int _flags = (flags); \ + zend_bool _strict = (EX_CALL_INFO() & ZEND_CALL_STRICT_TYPEHINTS) ? 1 : 0; \ + const int _flags = (flags) | (_strict ? ZEND_PARSE_PARAMS_STRICT : 0); \ int _min_num_args = (min_num_args); \ int _max_num_args = (max_num_args); \ int _num_args = EX_NUM_ARGS(); \ @@ -738,7 +741,7 @@ ZEND_API void zend_wrong_callback_error(int severity, int num, char *error); (UNEXPECTED(_num_args > _max_num_args) && \ EXPECTED(_max_num_args >= 0))) { \ if (!(_flags & ZEND_PARSE_PARAMS_QUIET)) { \ - zend_wrong_paramers_count_error(_num_args, _min_num_args, _max_num_args); \ + zend_wrong_paramers_count_error(_num_args, _min_num_args, _max_num_args, _strict); \ } \ error_code = ZPP_ERROR_FAILURE; \ break; \ @@ -754,11 +757,11 @@ ZEND_API void zend_wrong_callback_error(int severity, int num, char *error); if (UNEXPECTED(error_code != ZPP_ERROR_OK)) { \ if (!(_flags & ZEND_PARSE_PARAMS_QUIET)) { \ if (error_code == ZPP_ERROR_WRONG_CALLBACK) { \ - zend_wrong_callback_error(E_WARNING, _i, _error); \ + zend_wrong_callback_error(_strict ? E_RECOVERABLE_ERROR : E_WARNING, _i, _error); \ } else if (error_code == ZPP_ERROR_WRONG_CLASS) { \ - zend_wrong_paramer_class_error(_i, _error, _arg); \ + zend_wrong_paramer_class_error(_i, _error, _arg, _strict); \ } else if (error_code == ZPP_ERROR_WRONG_ARG) { \ - zend_wrong_paramer_type_error(_i, _expected_type, _arg); \ + zend_wrong_paramer_type_error(_i, _expected_type, _arg, _strict); \ } \ } \ failure; \ @@ -811,7 +814,7 @@ ZEND_API void zend_wrong_callback_error(int severity, int num, char *error); /* old "b" */ #define Z_PARAM_BOOL_EX(dest, is_null, check_null, separate) \ Z_PARAM_PROLOGUE(separate); \ - if (UNEXPECTED(!zend_parse_arg_bool(_arg, &dest, &is_null, check_null))) { \ + if (UNEXPECTED(!zend_parse_arg_bool(_arg, &dest, &is_null, check_null, _strict))) { \ _expected_type = Z_EXPECTED_BOOL; \ error_code = ZPP_ERROR_WRONG_ARG; \ break; \ @@ -823,7 +826,7 @@ ZEND_API void zend_wrong_callback_error(int severity, int num, char *error); /* old "C" */ #define Z_PARAM_CLASS_EX(dest, check_null, separate) \ Z_PARAM_PROLOGUE(separate); \ - if (UNEXPECTED(!zend_parse_arg_class(_arg, &dest, _i, check_null))) { \ + if (UNEXPECTED(!zend_parse_arg_class(_arg, &dest, _i, check_null, _strict))) { \ error_code = ZPP_ERROR_FAILURE; \ break; \ } @@ -834,7 +837,7 @@ ZEND_API void zend_wrong_callback_error(int severity, int num, char *error); /* old "d" */ #define Z_PARAM_DOUBLE_EX(dest, is_null, check_null, separate) \ Z_PARAM_PROLOGUE(separate); \ - if (UNEXPECTED(!zend_parse_arg_double(_arg, &dest, &is_null, check_null))) { \ + if (UNEXPECTED(!zend_parse_arg_double(_arg, &dest, &is_null, check_null, _strict))) { \ _expected_type = Z_EXPECTED_DOUBLE; \ error_code = ZPP_ERROR_WRONG_ARG; \ break; \ @@ -889,7 +892,7 @@ ZEND_API void zend_wrong_callback_error(int severity, int num, char *error); /* old "l" */ #define Z_PARAM_LONG_EX(dest, is_null, check_null, separate) \ Z_PARAM_PROLOGUE(separate); \ - if (UNEXPECTED(!zend_parse_arg_long(_arg, &dest, &is_null, check_null, 0))) { \ + if (UNEXPECTED(!zend_parse_arg_long(_arg, &dest, &is_null, check_null, 0, _strict))) { \ _expected_type = Z_EXPECTED_LONG; \ error_code = ZPP_ERROR_WRONG_ARG; \ break; \ @@ -901,7 +904,7 @@ ZEND_API void zend_wrong_callback_error(int severity, int num, char *error); /* old "L" */ #define Z_PARAM_STRICT_LONG_EX(dest, is_null, check_null, separate) \ Z_PARAM_PROLOGUE(separate); \ - if (UNEXPECTED(!zend_parse_arg_long(_arg, &dest, &is_null, check_null, 1))) { \ + if (UNEXPECTED(!zend_parse_arg_long(_arg, &dest, &is_null, check_null, 1, _strict))) { \ _expected_type = Z_EXPECTED_LONG; \ error_code = ZPP_ERROR_WRONG_ARG; \ break; \ @@ -943,7 +946,7 @@ ZEND_API void zend_wrong_callback_error(int severity, int num, char *error); /* old "p" */ #define Z_PARAM_PATH_EX(dest, dest_len, check_null, separate) \ Z_PARAM_PROLOGUE(separate); \ - if (UNEXPECTED(!zend_parse_arg_path(_arg, &dest, &dest_len, check_null))) { \ + if (UNEXPECTED(!zend_parse_arg_path(_arg, &dest, &dest_len, check_null, _strict))) { \ _expected_type = Z_EXPECTED_PATH; \ error_code = ZPP_ERROR_WRONG_ARG; \ break; \ @@ -955,7 +958,7 @@ ZEND_API void zend_wrong_callback_error(int severity, int num, char *error); /* old "P" */ #define Z_PARAM_PATH_STR_EX(dest, check_null, separate) \ Z_PARAM_PROLOGUE(separate); \ - if (UNEXPECTED(!zend_parse_arg_path_str(_arg, &dest, check_null))) { \ + if (UNEXPECTED(!zend_parse_arg_path_str(_arg, &dest, check_null, _strict))) { \ _expected_type = Z_EXPECTED_PATH; \ error_code = ZPP_ERROR_WRONG_ARG; \ break; \ @@ -979,7 +982,7 @@ ZEND_API void zend_wrong_callback_error(int severity, int num, char *error); /* old "s" */ #define Z_PARAM_STRING_EX(dest, dest_len, check_null, separate) \ Z_PARAM_PROLOGUE(separate); \ - if (UNEXPECTED(!zend_parse_arg_string(_arg, &dest, &dest_len, check_null))) { \ + if (UNEXPECTED(!zend_parse_arg_string(_arg, &dest, &dest_len, check_null, _strict))) { \ _expected_type = Z_EXPECTED_STRING; \ error_code = ZPP_ERROR_WRONG_ARG; \ break; \ @@ -991,7 +994,7 @@ ZEND_API void zend_wrong_callback_error(int severity, int num, char *error); /* old "S" */ #define Z_PARAM_STR_EX(dest, check_null, separate) \ Z_PARAM_PROLOGUE(separate); \ - if (UNEXPECTED(!zend_parse_arg_str(_arg, &dest, check_null))) { \ + if (UNEXPECTED(!zend_parse_arg_str(_arg, &dest, check_null, _strict))) { \ _expected_type = Z_EXPECTED_STRING; \ error_code = ZPP_ERROR_WRONG_ARG; \ break; \ @@ -1046,13 +1049,18 @@ ZEND_API void zend_wrong_callback_error(int severity, int num, char *error); /* Inlined implementations shared by new and old parameter parsing APIs */ ZEND_API int parse_arg_object_to_str(zval *arg, zend_string **str, int type); -ZEND_API int zend_parse_arg_class(zval *arg, zend_class_entry **pce, int num, int check_null); +ZEND_API int zend_parse_arg_class(zval *arg, zend_class_entry **pce, int num, int check_null, zend_bool strict); -static zend_always_inline int zend_parse_arg_bool(zval *arg, zend_bool *dest, zend_bool *is_null, int check_null) +static zend_always_inline int zend_parse_arg_bool(zval *arg, zend_bool *dest, zend_bool *is_null, int check_null, zend_bool strict) { if (check_null) { *is_null = 0; } + + if (UNEXPECTED(strict && Z_TYPE_P(arg) != IS_TRUE && Z_TYPE_P(arg) != IS_FALSE && !(check_null && Z_TYPE_P(arg) == IS_NULL))) { + return 0; + } + if (EXPECTED(Z_TYPE_P(arg) == IS_TRUE)) { *dest = 1; } else if (EXPECTED(Z_TYPE_P(arg) < IS_TRUE)) { @@ -1068,11 +1076,16 @@ static zend_always_inline int zend_parse_arg_bool(zval *arg, zend_bool *dest, ze return 1; } -static zend_always_inline int zend_parse_arg_long(zval *arg, zend_long *dest, zend_bool *is_null, int check_null, int strict) +static zend_always_inline int zend_parse_arg_long(zval *arg, zend_long *dest, zend_bool *is_null, int check_null, int cap, zend_bool strict) { if (check_null) { *is_null = 0; } + + if (UNEXPECTED(strict && Z_TYPE_P(arg) != IS_LONG && !(check_null && Z_TYPE_P(arg) == IS_NULL))) { + return 0; + } + if (EXPECTED(Z_TYPE_P(arg) == IS_LONG)) { *dest = Z_LVAL_P(arg); } else if (EXPECTED(Z_TYPE_P(arg) == IS_DOUBLE)) { @@ -1080,8 +1093,7 @@ static zend_always_inline int zend_parse_arg_long(zval *arg, zend_long *dest, ze return 0; } if (UNEXPECTED(!ZEND_DOUBLE_FITS_LONG(Z_DVAL_P(arg)))) { - /* Ironically, the strict parameter makes zpp *non*-strict here */ - if (strict) { + if (cap) { *dest = (Z_DVAL_P(arg) > 0) ? ZEND_LONG_MAX : ZEND_LONG_MIN; } else { return 0; @@ -1099,7 +1111,7 @@ static zend_always_inline int zend_parse_arg_long(zval *arg, zend_long *dest, ze return 0; } if (UNEXPECTED(!ZEND_DOUBLE_FITS_LONG(d))) { - if (strict) { + if (cap) { *dest = (d > 0) ? ZEND_LONG_MAX : ZEND_LONG_MIN; } else { return 0; @@ -1124,11 +1136,16 @@ static zend_always_inline int zend_parse_arg_long(zval *arg, zend_long *dest, ze return 1; } -static zend_always_inline int zend_parse_arg_double(zval *arg, double *dest, zend_bool *is_null, int check_null) +static zend_always_inline int zend_parse_arg_double(zval *arg, double *dest, zend_bool *is_null, int check_null, zend_bool strict) { if (check_null) { *is_null = 0; } + + if (UNEXPECTED(strict && Z_TYPE_P(arg) != IS_DOUBLE && !(check_null && Z_TYPE_P(arg) == IS_NULL))) { + return 0; + } + if (EXPECTED(Z_TYPE_P(arg) == IS_DOUBLE)) { *dest = Z_DVAL_P(arg); } else if (EXPECTED(Z_TYPE_P(arg) == IS_LONG)) { @@ -1157,8 +1174,12 @@ static zend_always_inline int zend_parse_arg_double(zval *arg, double *dest, zen return 1; } -static zend_always_inline int zend_parse_arg_str(zval *arg, zend_string **dest, int check_null) +static zend_always_inline int zend_parse_arg_str(zval *arg, zend_string **dest, int check_null, zend_bool strict) { + if (UNEXPECTED(strict && Z_TYPE_P(arg) != IS_STRING && !(check_null && Z_TYPE_P(arg) == IS_NULL))) { + return 0; + } + if (EXPECTED(Z_TYPE_P(arg) == IS_STRING)) { *dest = Z_STR_P(arg); } else if (EXPECTED(Z_TYPE_P(arg) < IS_STRING)) { @@ -1179,11 +1200,11 @@ static zend_always_inline int zend_parse_arg_str(zval *arg, zend_string **dest, return 1; } -static zend_always_inline int zend_parse_arg_string(zval *arg, char **dest, size_t *dest_len, int check_null) +static zend_always_inline int zend_parse_arg_string(zval *arg, char **dest, size_t *dest_len, int check_null, zend_bool strict) { zend_string *str; - if (!zend_parse_arg_str(arg, &str, check_null)) { + if (!zend_parse_arg_str(arg, &str, check_null, strict)) { return 0; } if (check_null && UNEXPECTED(!str)) { @@ -1196,20 +1217,20 @@ static zend_always_inline int zend_parse_arg_string(zval *arg, char **dest, size return 1; } -static zend_always_inline int zend_parse_arg_path_str(zval *arg, zend_string **dest, int check_null) +static zend_always_inline int zend_parse_arg_path_str(zval *arg, zend_string **dest, int check_null, zend_bool strict) { - if (!zend_parse_arg_str(arg, dest, check_null) || + if (!zend_parse_arg_str(arg, dest, check_null, strict) || (*dest && UNEXPECTED(CHECK_NULL_PATH((*dest)->val, (*dest)->len)))) { return 0; } return 1; } -static zend_always_inline int zend_parse_arg_path(zval *arg, char **dest, size_t *dest_len, int check_null) +static zend_always_inline int zend_parse_arg_path(zval *arg, char **dest, size_t *dest_len, int check_null, zend_bool strict) { zend_string *str; - if (!zend_parse_arg_path_str(arg, &str, check_null)) { + if (!zend_parse_arg_path_str(arg, &str, check_null, strict)) { return 0; } if (check_null && UNEXPECTED(!str)) { diff --git a/Zend/zend_execute.c b/Zend/zend_execute.c index 604303ae10d..823412c7bb6 100644 --- a/Zend/zend_execute.c +++ b/Zend/zend_execute.c @@ -610,13 +610,13 @@ static int is_null_constant(zval *default_value) return 0; } -static zend_bool zend_verify_scalar_type_hint(zend_uchar type_hint, zval *arg) +static zend_bool zend_verify_scalar_type_hint(zend_uchar type_hint, zval *arg, zend_bool strict) { switch (type_hint) { case _IS_BOOL: { zend_bool dest; - if (!zend_parse_arg_bool(arg, &dest, NULL, 0)) { + if (!zend_parse_arg_bool(arg, &dest, NULL, 0, strict)) { return 0; } zval_ptr_dtor(arg); @@ -626,7 +626,7 @@ static zend_bool zend_verify_scalar_type_hint(zend_uchar type_hint, zval *arg) case IS_LONG: { zend_long dest; - if (!zend_parse_arg_long(arg, &dest, NULL, 0, 0)) { + if (!zend_parse_arg_long(arg, &dest, NULL, 0, 0, strict)) { return 0; } zval_ptr_dtor(arg); @@ -636,7 +636,7 @@ static zend_bool zend_verify_scalar_type_hint(zend_uchar type_hint, zval *arg) case IS_DOUBLE: { double dest; - if (!zend_parse_arg_double(arg, &dest, NULL, 0)) { + if (!zend_parse_arg_double(arg, &dest, NULL, 0, strict)) { return 0; } zval_ptr_dtor(arg); @@ -646,7 +646,7 @@ static zend_bool zend_verify_scalar_type_hint(zend_uchar type_hint, zval *arg) case IS_STRING: { zend_string *dest; - if (!zend_parse_arg_str(arg, &dest, 0)) { + if (!zend_parse_arg_str(arg, &dest, 0, strict)) { return 0; } zval_ptr_dtor(arg); @@ -695,7 +695,7 @@ static void zend_verify_internal_arg_type(zend_function *zf, uint32_t arg_num, z if (!zend_is_callable(arg, IS_CALLABLE_CHECK_SILENT, NULL) && (Z_TYPE_P(arg) != IS_NULL || !cur_arg_info->allow_null)) { zend_verify_arg_error(E_RECOVERABLE_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)))) { + } 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: @@ -703,7 +703,7 @@ failure: } return; } - if (strict || !zend_verify_scalar_type_hint(cur_arg_info->type_hint, arg)) { + if (!zend_verify_scalar_type_hint(cur_arg_info->type_hint, arg, strict)) { goto failure; } } @@ -755,7 +755,7 @@ failure: } return; } - if (strict || !zend_verify_scalar_type_hint(cur_arg_info->type_hint, arg)) { + if (!zend_verify_scalar_type_hint(cur_arg_info->type_hint, arg, strict)) { goto failure; } }