diff options
Diffstat (limited to 'Zend/zend_API.c')
-rw-r--r-- | Zend/zend_API.c | 1921 |
1 files changed, 940 insertions, 981 deletions
diff --git a/Zend/zend_API.c b/Zend/zend_API.c index de03cf5656..cc31a81a1c 100644 --- a/Zend/zend_API.c +++ b/Zend/zend_API.c @@ -42,10 +42,10 @@ static zend_module_entry **module_post_deactivate_handlers; static zend_class_entry **class_cleanup_handlers; -ZEND_API int _zend_get_parameters_array_ex(int param_count, zval *argument_array) /* {{{ */ +ZEND_API zend_result _zend_get_parameters_array_ex(uint32_t param_count, zval *argument_array) /* {{{ */ { zval *param_ptr; - int arg_count; + uint32_t arg_count; param_ptr = ZEND_CALL_ARG(EG(current_execute_data), 1); arg_count = ZEND_CALL_NUM_ARGS(EG(current_execute_data)); @@ -64,10 +64,10 @@ ZEND_API int _zend_get_parameters_array_ex(int param_count, zval *argument_array } /* }}} */ -ZEND_API int zend_copy_parameters_array(int param_count, zval *argument_array) /* {{{ */ +ZEND_API zend_result zend_copy_parameters_array(uint32_t param_count, zval *argument_array) /* {{{ */ { zval *param_ptr; - int arg_count; + uint32_t arg_count; param_ptr = ZEND_CALL_ARG(EG(current_execute_data), 1); arg_count = ZEND_CALL_NUM_ARGS(EG(current_execute_data)); @@ -91,12 +91,12 @@ ZEND_API ZEND_COLD void zend_wrong_param_count(void) /* {{{ */ const char *space; const char *class_name = get_active_class_name(&space); - zend_internal_argument_count_error(ZEND_ARG_USES_STRICT_TYPES(), "Wrong parameter count for %s%s%s()", class_name, space, get_active_function_name()); + zend_argument_count_error("Wrong parameter count for %s%s%s()", class_name, space, get_active_function_name()); } /* }}} */ /* Argument parsing API -- andrei */ -ZEND_API char *zend_get_type_by_const(int type) /* {{{ */ +ZEND_API const char *zend_get_type_by_const(int type) /* {{{ */ { switch(type) { case IS_FALSE: @@ -123,22 +123,34 @@ ZEND_API char *zend_get_type_by_const(int type) /* {{{ */ return "array"; case IS_VOID: return "void"; + case IS_MIXED: + return "mixed"; case _IS_NUMBER: return "number"; - default: - return "unknown"; + EMPTY_SWITCH_DEFAULT_CASE() } } /* }}} */ -ZEND_API char *zend_zval_type_name(const zval *arg) /* {{{ */ +ZEND_API const char *zend_zval_type_name(const zval *arg) /* {{{ */ { ZVAL_DEREF(arg); + + if (Z_ISUNDEF_P(arg)) { + return "null"; + } + + if (Z_TYPE_P(arg) == IS_OBJECT) { + return ZSTR_VAL(Z_OBJCE_P(arg)->name); + } + return zend_get_type_by_const(Z_TYPE_P(arg)); } /* }}} */ -ZEND_API zend_string *zend_zval_get_type(const zval *arg) /* {{{ */ +/* This API exists *only* for use in gettype(). + * For anything else, you likely want zend_zval_type_name(). */ +ZEND_API zend_string *zend_zval_get_legacy_type(const zval *arg) /* {{{ */ { switch (Z_TYPE_P(arg)) { case IS_NULL: @@ -168,54 +180,28 @@ ZEND_API zend_string *zend_zval_get_type(const zval *arg) /* {{{ */ } /* }}} */ -ZEND_API ZEND_COLD int ZEND_FASTCALL zend_wrong_parameters_none_error(void) /* {{{ */ +ZEND_API ZEND_COLD void ZEND_FASTCALL zend_wrong_parameters_none_error(void) /* {{{ */ { int num_args = ZEND_CALL_NUM_ARGS(EG(current_execute_data)); zend_function *active_function = EG(current_execute_data)->func; const char *class_name = active_function->common.scope ? ZSTR_VAL(active_function->common.scope->name) : ""; - zend_internal_argument_count_error( - ZEND_ARG_USES_STRICT_TYPES(), - "%s%s%s() expects %s %d parameter%s, %d given", + zend_argument_count_error( + "%s%s%s() expects exactly 0 parameters, %d given", class_name, \ class_name[0] ? "::" : "", \ ZSTR_VAL(active_function->common.function_name), - "exactly", - 0, - "s", num_args); - return FAILURE; } /* }}} */ -ZEND_API ZEND_COLD int ZEND_FASTCALL zend_wrong_parameters_none_exception(void) /* {{{ */ +ZEND_API ZEND_COLD void ZEND_FASTCALL zend_wrong_parameters_count_error(uint32_t min_num_args, uint32_t max_num_args) /* {{{ */ { - int num_args = ZEND_CALL_NUM_ARGS(EG(current_execute_data)); + uint32_t num_args = ZEND_CALL_NUM_ARGS(EG(current_execute_data)); zend_function *active_function = EG(current_execute_data)->func; const char *class_name = active_function->common.scope ? ZSTR_VAL(active_function->common.scope->name) : ""; - zend_internal_argument_count_error( - 1, - "%s%s%s() expects %s %d parameter%s, %d given", - class_name, \ - class_name[0] ? "::" : "", \ - ZSTR_VAL(active_function->common.function_name), - "exactly", - 0, - "s", - num_args); - return FAILURE; -} -/* }}} */ - -ZEND_API ZEND_COLD void ZEND_FASTCALL zend_wrong_parameters_count_error(int min_num_args, int max_num_args) /* {{{ */ -{ - int num_args = ZEND_CALL_NUM_ARGS(EG(current_execute_data)); - zend_function *active_function = EG(current_execute_data)->func; - const char *class_name = active_function->common.scope ? ZSTR_VAL(active_function->common.scope->name) : ""; - - zend_internal_argument_count_error( - ZEND_ARG_USES_STRICT_TYPES(), + zend_argument_count_error( "%s%s%s() expects %s %d parameter%s, %d given", class_name, \ class_name[0] ? "::" : "", \ @@ -227,29 +213,38 @@ ZEND_API ZEND_COLD void ZEND_FASTCALL zend_wrong_parameters_count_error(int min_ } /* }}} */ -ZEND_API ZEND_COLD void ZEND_FASTCALL zend_wrong_parameters_count_exception(int min_num_args, int max_num_args) /* {{{ */ +ZEND_API ZEND_COLD void ZEND_FASTCALL zend_wrong_parameter_error(int error_code, uint32_t num, char *name, zend_expected_type expected_type, zval *arg) /* {{{ */ { - int num_args = ZEND_CALL_NUM_ARGS(EG(current_execute_data)); - zend_function *active_function = EG(current_execute_data)->func; - const char *class_name = active_function->common.scope ? ZSTR_VAL(active_function->common.scope->name) : ""; - - zend_internal_argument_count_error( - 1, - "%s%s%s() expects %s %d parameter%s, %d given", - class_name, \ - class_name[0] ? "::" : "", \ - ZSTR_VAL(active_function->common.function_name), - min_num_args == max_num_args ? "exactly" : num_args < min_num_args ? "at least" : "at most", - num_args < min_num_args ? min_num_args : max_num_args, - (num_args < min_num_args ? min_num_args : max_num_args) == 1 ? "" : "s", - num_args); + switch (error_code) { + case ZPP_ERROR_WRONG_CALLBACK: + zend_wrong_callback_error(num, name); + break; + case ZPP_ERROR_WRONG_CLASS: + zend_wrong_parameter_class_error(num, name, arg); + break; + case ZPP_ERROR_WRONG_CLASS_OR_NULL: + zend_wrong_parameter_class_or_null_error(num, name, arg); + break; + case ZPP_ERROR_WRONG_ARG: + zend_wrong_parameter_type_error(num, expected_type, arg); + break; + case ZPP_ERROR_WRONG_STRING_OR_CLASS: + zend_wrong_parameter_string_or_class_error(num, name, arg); + break; + case ZPP_ERROR_WRONG_STRING_OR_CLASS_OR_NULL: + zend_wrong_parameter_string_or_class_or_null_error(num, name, arg); + break; + case ZPP_ERROR_UNEXPECTED_EXTRA_NAMED: + zend_unexpected_extra_named_error(); + break; + default: + ZEND_ASSERT(error_code != ZPP_ERROR_OK); + } } /* }}} */ -ZEND_API ZEND_COLD void ZEND_FASTCALL zend_wrong_parameter_type_error(int num, zend_expected_type expected_type, zval *arg) /* {{{ */ +ZEND_API ZEND_COLD void ZEND_FASTCALL zend_wrong_parameter_type_error(uint32_t num, zend_expected_type expected_type, zval *arg) /* {{{ */ { - const char *space; - const char *class_name; static const char * const expected_error[] = { Z_EXPECTED_TYPES(Z_EXPECTED_TYPE_STR) NULL @@ -258,100 +253,123 @@ ZEND_API ZEND_COLD void ZEND_FASTCALL zend_wrong_parameter_type_error(int num, z if (EG(exception)) { return; } - class_name = get_active_class_name(&space); - zend_internal_type_error(ZEND_ARG_USES_STRICT_TYPES(), "%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_argument_type_error(num, "must be %s, %s given", expected_error[expected_type], zend_zval_type_name(arg)); } /* }}} */ -ZEND_API ZEND_COLD void ZEND_FASTCALL zend_wrong_parameter_type_exception(int num, zend_expected_type expected_type, zval *arg) /* {{{ */ +ZEND_API ZEND_COLD void ZEND_FASTCALL zend_wrong_parameter_class_error(uint32_t num, const char *name, zval *arg) /* {{{ */ { - const char *space; - const char *class_name; - static const char * const expected_error[] = { - Z_EXPECTED_TYPES(Z_EXPECTED_TYPE_STR) - NULL - }; - if (EG(exception)) { return; } - class_name = get_active_class_name(&space); - zend_internal_type_error(1, "%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_argument_type_error(num, "must be of type %s, %s given", name, zend_zval_type_name(arg)); } /* }}} */ -ZEND_API ZEND_COLD void ZEND_FASTCALL zend_wrong_parameter_class_error(int num, char *name, zval *arg) /* {{{ */ +ZEND_API ZEND_COLD void ZEND_FASTCALL zend_wrong_parameter_class_or_null_error(uint32_t num, const char *name, zval *arg) /* {{{ */ { - const char *space; - const char *class_name; - if (EG(exception)) { return; } - class_name = get_active_class_name(&space); - zend_internal_type_error(ZEND_ARG_USES_STRICT_TYPES(), "%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)); + + zend_argument_type_error(num, "must be of type ?%s, %s given", name, zend_zval_type_name(arg)); } /* }}} */ -ZEND_API ZEND_COLD void ZEND_FASTCALL zend_wrong_parameter_class_exception(int num, char *name, zval *arg) /* {{{ */ +ZEND_API ZEND_COLD void ZEND_FASTCALL zend_wrong_parameter_string_or_class_error(uint32_t num, const char *name, zval *arg) /* {{{ */ { - const char *space; - const char *class_name; - if (EG(exception)) { return; } - class_name = get_active_class_name(&space); - zend_internal_type_error(1, "%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)); + + zend_argument_type_error(num, "must be of type %s|string, %s given", name, zend_zval_type_name(arg)); } /* }}} */ -ZEND_API ZEND_COLD void ZEND_FASTCALL zend_wrong_callback_error(int num, char *error) /* {{{ */ +ZEND_API ZEND_COLD void ZEND_FASTCALL zend_wrong_parameter_string_or_class_or_null_error(uint32_t num, const char *name, zval *arg) /* {{{ */ { - const char *space; - const char *class_name; + if (EG(exception)) { + return; + } + + zend_argument_type_error(num, "must be of type %s|string|null, %s given", name, zend_zval_type_name(arg)); +} +/* }}} */ +ZEND_API ZEND_COLD void ZEND_FASTCALL zend_wrong_callback_error(uint32_t num, char *error) /* {{{ */ +{ if (EG(exception)) { return; } - class_name = get_active_class_name(&space); - zend_internal_type_error(ZEND_ARG_USES_STRICT_TYPES(), "%s%s%s() expects parameter %d to be a valid callback, %s", - class_name, space, get_active_function_name(), num, error); + + zend_argument_type_error(num, "must be a valid callback, %s", error); efree(error); } /* }}} */ -ZEND_API ZEND_COLD void ZEND_FASTCALL zend_wrong_callback_exception(int num, char *error) /* {{{ */ +ZEND_API ZEND_COLD void ZEND_FASTCALL zend_unexpected_extra_named_error(void) { const char *space; - const char *class_name; + const char *class_name = get_active_class_name(&space); + zend_argument_count_error("%s%s%s() does not accept unknown named parameters", + class_name, space, get_active_function_name()); +} +static ZEND_COLD void ZEND_FASTCALL zend_argument_error_variadic(zend_class_entry *error_ce, uint32_t arg_num, const char *format, va_list va) /* {{{ */ +{ + const char *space; + const char *class_name; + const char *arg_name; + char *message = NULL; if (EG(exception)) { return; } + class_name = get_active_class_name(&space); - zend_internal_type_error(1, "%s%s%s() expects parameter %d to be a valid callback, %s", - class_name, space, get_active_function_name(), num, error); - efree(error); + arg_name = get_active_function_arg_name(arg_num); + + zend_vspprintf(&message, 0, format, va); + zend_throw_error(error_ce, "%s%s%s(): Argument #%d%s%s%s %s", + class_name, space, get_active_function_name(), arg_num, + arg_name ? " ($" : "", arg_name ? arg_name : "", arg_name ? ")" : "", message + ); + efree(message); } /* }}} */ -ZEND_API ZEND_COLD void ZEND_FASTCALL zend_wrong_callback_deprecated(int num, char *error) /* {{{ */ +ZEND_API ZEND_COLD void zend_argument_error(zend_class_entry *error_ce, uint32_t arg_num, const char *format, ...) /* {{{ */ { - const char *space; - const char *class_name = get_active_class_name(&space); + va_list va; - zend_error(E_DEPRECATED, "%s%s%s() expects parameter %d to be a valid callback, %s", - class_name, space, get_active_function_name(), num, error); - efree(error); + va_start(va, format); + zend_argument_error_variadic(error_ce, arg_num, format, va); + va_end(va); } /* }}} */ -ZEND_API int ZEND_FASTCALL zend_parse_arg_class(zval *arg, zend_class_entry **pce, int num, int check_null) /* {{{ */ +ZEND_API ZEND_COLD void zend_argument_type_error(uint32_t arg_num, const char *format, ...) /* {{{ */ +{ + va_list va; + + va_start(va, format); + zend_argument_error_variadic(zend_ce_type_error, arg_num, format, va); + va_end(va); +} +/* }}} */ + +ZEND_API ZEND_COLD void zend_argument_value_error(uint32_t arg_num, const char *format, ...) /* {{{ */ +{ + va_list va; + + va_start(va, format); + zend_argument_error_variadic(zend_ce_value_error, arg_num, format, va); + va_end(va); +} +/* }}} */ + +ZEND_API bool ZEND_FASTCALL zend_parse_arg_class(zval *arg, zend_class_entry **pce, uint32_t num, bool check_null) /* {{{ */ { zend_class_entry *ce_base = *pce; @@ -367,30 +385,20 @@ ZEND_API int ZEND_FASTCALL zend_parse_arg_class(zval *arg, zend_class_entry **pc *pce = zend_lookup_class(Z_STR_P(arg)); if (ce_base) { if ((!*pce || !instanceof_function(*pce, ce_base))) { - const char *space; - const char *class_name = get_active_class_name(&space); - - zend_internal_type_error(ZEND_ARG_USES_STRICT_TYPES(), "%s%s%s() expects parameter %d to be a class name derived from %s, '%s' given", - class_name, space, get_active_function_name(), num, - ZSTR_VAL(ce_base->name), Z_STRVAL_P(arg)); + zend_argument_type_error(num, "must be a class name derived from %s, %s given", ZSTR_VAL(ce_base->name), Z_STRVAL_P(arg)); *pce = NULL; return 0; } } if (!*pce) { - const char *space; - const char *class_name = get_active_class_name(&space); - - zend_internal_type_error(ZEND_ARG_USES_STRICT_TYPES(), "%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)); + zend_argument_type_error(num, "must be a valid class name, %s given", Z_STRVAL_P(arg)); return 0; } return 1; } /* }}} */ -ZEND_API int ZEND_FASTCALL zend_parse_arg_bool_weak(zval *arg, zend_bool *dest) /* {{{ */ +ZEND_API bool ZEND_FASTCALL zend_parse_arg_bool_weak(zval *arg, zend_bool *dest) /* {{{ */ { if (EXPECTED(Z_TYPE_P(arg) <= IS_STRING)) { *dest = zend_is_true(arg); @@ -401,7 +409,7 @@ ZEND_API int ZEND_FASTCALL zend_parse_arg_bool_weak(zval *arg, zend_bool *dest) } /* }}} */ -ZEND_API int ZEND_FASTCALL zend_parse_arg_bool_slow(zval *arg, zend_bool *dest) /* {{{ */ +ZEND_API bool ZEND_FASTCALL zend_parse_arg_bool_slow(zval *arg, zend_bool *dest) /* {{{ */ { if (UNEXPECTED(ZEND_ARG_USES_STRICT_TYPES())) { return 0; @@ -410,7 +418,7 @@ ZEND_API int ZEND_FASTCALL zend_parse_arg_bool_slow(zval *arg, zend_bool *dest) } /* }}} */ -ZEND_API int ZEND_FASTCALL zend_parse_arg_long_weak(zval *arg, zend_long *dest) /* {{{ */ +ZEND_API bool ZEND_FASTCALL zend_parse_arg_long_weak(zval *arg, zend_long *dest) /* {{{ */ { if (EXPECTED(Z_TYPE_P(arg) == IS_DOUBLE)) { if (UNEXPECTED(zend_isnan(Z_DVAL_P(arg)))) { @@ -423,7 +431,7 @@ ZEND_API int ZEND_FASTCALL zend_parse_arg_long_weak(zval *arg, zend_long *dest) } } else if (EXPECTED(Z_TYPE_P(arg) == IS_STRING)) { double d; - int type; + zend_uchar type; if (UNEXPECTED((type = is_numeric_str_function(Z_STR_P(arg), dest, &d)) != IS_LONG)) { if (EXPECTED(type != 0)) { @@ -453,7 +461,7 @@ ZEND_API int ZEND_FASTCALL zend_parse_arg_long_weak(zval *arg, zend_long *dest) } /* }}} */ -ZEND_API int ZEND_FASTCALL zend_parse_arg_long_slow(zval *arg, zend_long *dest) /* {{{ */ +ZEND_API bool ZEND_FASTCALL zend_parse_arg_long_slow(zval *arg, zend_long *dest) /* {{{ */ { if (UNEXPECTED(ZEND_ARG_USES_STRICT_TYPES())) { return 0; @@ -462,57 +470,13 @@ ZEND_API int ZEND_FASTCALL zend_parse_arg_long_slow(zval *arg, zend_long *dest) } /* }}} */ -ZEND_API int ZEND_FASTCALL zend_parse_arg_long_cap_weak(zval *arg, zend_long *dest) /* {{{ */ -{ - if (EXPECTED(Z_TYPE_P(arg) == IS_DOUBLE)) { - if (UNEXPECTED(zend_isnan(Z_DVAL_P(arg)))) { - return 0; - } - *dest = zend_dval_to_lval_cap(Z_DVAL_P(arg)); - } else if (EXPECTED(Z_TYPE_P(arg) == IS_STRING)) { - double d; - int type; - - if (UNEXPECTED((type = is_numeric_str_function(Z_STR_P(arg), dest, &d)) != IS_LONG)) { - if (EXPECTED(type != 0)) { - if (UNEXPECTED(zend_isnan(d))) { - return 0; - } - *dest = zend_dval_to_lval_cap(d); - } else { - return 0; - } - } - if (UNEXPECTED(EG(exception))) { - return 0; - } - } else if (EXPECTED(Z_TYPE_P(arg) < IS_TRUE)) { - *dest = 0; - } else if (EXPECTED(Z_TYPE_P(arg) == IS_TRUE)) { - *dest = 1; - } else { - return 0; - } - return 1; -} -/* }}} */ - -ZEND_API int ZEND_FASTCALL zend_parse_arg_long_cap_slow(zval *arg, zend_long *dest) /* {{{ */ -{ - if (UNEXPECTED(ZEND_ARG_USES_STRICT_TYPES())) { - return 0; - } - return zend_parse_arg_long_cap_weak(arg, dest); -} -/* }}} */ - -ZEND_API int ZEND_FASTCALL zend_parse_arg_double_weak(zval *arg, double *dest) /* {{{ */ +ZEND_API bool ZEND_FASTCALL zend_parse_arg_double_weak(zval *arg, double *dest) /* {{{ */ { if (EXPECTED(Z_TYPE_P(arg) == IS_LONG)) { *dest = (double)Z_LVAL_P(arg); } else if (EXPECTED(Z_TYPE_P(arg) == IS_STRING)) { zend_long l; - int type; + zend_uchar type; if (UNEXPECTED((type = is_numeric_str_function(Z_STR_P(arg), &l, dest)) != IS_DOUBLE)) { if (EXPECTED(type != 0)) { @@ -535,7 +499,7 @@ ZEND_API int ZEND_FASTCALL zend_parse_arg_double_weak(zval *arg, double *dest) / } /* }}} */ -ZEND_API int ZEND_FASTCALL zend_parse_arg_double_slow(zval *arg, double *dest) /* {{{ */ +ZEND_API bool ZEND_FASTCALL zend_parse_arg_double_slow(zval *arg, double *dest) /* {{{ */ { if (EXPECTED(Z_TYPE_P(arg) == IS_LONG)) { /* SSTH Exception: IS_LONG may be accepted instead as IS_DOUBLE */ @@ -547,36 +511,49 @@ ZEND_API int ZEND_FASTCALL zend_parse_arg_double_slow(zval *arg, double *dest) / } /* }}} */ -ZEND_API int ZEND_FASTCALL zend_parse_arg_str_weak(zval *arg, zend_string **dest) /* {{{ */ +ZEND_API bool ZEND_FASTCALL zend_parse_arg_number_slow(zval *arg, zval **dest) /* {{{ */ +{ + if (UNEXPECTED(ZEND_ARG_USES_STRICT_TYPES())) { + return 0; + } + if (Z_TYPE_P(arg) == IS_STRING) { + zend_string *str = Z_STR_P(arg); + zend_long lval; + double dval; + zend_uchar type = is_numeric_str_function(str, &lval, &dval); + if (type == IS_LONG) { + ZVAL_LONG(arg, lval); + } else if (type == IS_DOUBLE) { + ZVAL_DOUBLE(arg, dval); + } else { + return 0; + } + zend_string_release(str); + } else if (Z_TYPE_P(arg) < IS_TRUE) { + ZVAL_LONG(arg, 0); + } else if (Z_TYPE_P(arg) == IS_TRUE) { + ZVAL_LONG(arg, 1); + } else { + return 0; + } + *dest = arg; + return 1; +} +/* }}} */ + +ZEND_API bool ZEND_FASTCALL zend_parse_arg_str_weak(zval *arg, zend_string **dest) /* {{{ */ { if (EXPECTED(Z_TYPE_P(arg) < IS_STRING)) { convert_to_string(arg); *dest = Z_STR_P(arg); } else if (UNEXPECTED(Z_TYPE_P(arg) == IS_OBJECT)) { - if (Z_OBJ_HANDLER_P(arg, cast_object)) { - zval obj; - if (Z_OBJ_HANDLER_P(arg, cast_object)(arg, &obj, IS_STRING) == SUCCESS) { - zval_ptr_dtor(arg); - ZVAL_COPY_VALUE(arg, &obj); - *dest = Z_STR_P(arg); - return 1; - } - } else if (Z_OBJ_HANDLER_P(arg, get)) { - zval rv; - zval *z = Z_OBJ_HANDLER_P(arg, get)(arg, &rv); - - if (Z_TYPE_P(z) != IS_OBJECT) { - zval_ptr_dtor(arg); - if (Z_TYPE_P(z) == IS_STRING) { - ZVAL_COPY_VALUE(arg, z); - } else { - ZVAL_STR(arg, zval_get_string_func(z)); - zval_ptr_dtor(z); - } - *dest = Z_STR_P(arg); - return 1; - } - zval_ptr_dtor(z); + zend_object *zobj = Z_OBJ_P(arg); + zval obj; + if (zobj->handlers->cast_object(zobj, &obj, IS_STRING) == SUCCESS) { + OBJ_RELEASE(zobj); + ZVAL_COPY_VALUE(arg, &obj); + *dest = Z_STR_P(arg); + return 1; } return 0; } else { @@ -586,7 +563,7 @@ ZEND_API int ZEND_FASTCALL zend_parse_arg_str_weak(zval *arg, zend_string **dest } /* }}} */ -ZEND_API int ZEND_FASTCALL zend_parse_arg_str_slow(zval *arg, zend_string **dest) /* {{{ */ +ZEND_API bool ZEND_FASTCALL zend_parse_arg_str_slow(zval *arg, zend_string **dest) /* {{{ */ { if (UNEXPECTED(ZEND_ARG_USES_STRICT_TYPES())) { return 0; @@ -595,12 +572,29 @@ ZEND_API int ZEND_FASTCALL zend_parse_arg_str_slow(zval *arg, zend_string **dest } /* }}} */ -static const char *zend_parse_arg_impl(int arg_num, zval *arg, va_list *va, const char **spec, char **error, int *severity) /* {{{ */ +ZEND_API bool ZEND_FASTCALL zend_parse_arg_str_or_long_slow(zval *arg, zend_string **dest_str, zend_long *dest_long) /* {{{ */ +{ + if (UNEXPECTED(ZEND_ARG_USES_STRICT_TYPES())) { + return 0; + } + if (zend_parse_arg_long_weak(arg, dest_long)) { + *dest_str = NULL; + return 1; + } else if (zend_parse_arg_str_weak(arg, dest_str)) { + *dest_long = 0; + return 1; + } else { + return 0; + } +} +/* }}} */ + +static const char *zend_parse_arg_impl(zval *arg, va_list *va, const char **spec, char **error) /* {{{ */ { const char *spec_walk = *spec; char c = *spec_walk++; - int check_null = 0; - int separate = 0; + bool check_null = 0; + bool separate = 0; zval *real_arg = arg; /* scan through modifiers */ @@ -620,7 +614,6 @@ static const char *zend_parse_arg_impl(int arg_num, zval *arg, va_list *va, cons switch (c) { case 'l': - case 'L': { zend_long *p = va_arg(*va, zend_long *); zend_bool *is_null = NULL; @@ -629,8 +622,8 @@ 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')) { - return "int"; + if (!zend_parse_arg_long(arg, p, is_null, check_null)) { + return check_null ? "?int" : "int"; } } break; @@ -645,7 +638,17 @@ static const char *zend_parse_arg_impl(int arg_num, zval *arg, va_list *va, cons } if (!zend_parse_arg_double(arg, p, is_null, check_null)) { - return "float"; + return check_null ? "?float" : "float"; + } + } + break; + + case 'n': + { + zval **p = va_arg(*va, zval **); + + if (!zend_parse_arg_number(arg, p, check_null)) { + return check_null ? "int|float|null" : "int|float"; } } break; @@ -655,7 +658,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)) { - return "string"; + return check_null ? "?string" : "string"; } } break; @@ -665,7 +668,10 @@ 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)) { - return "a valid path"; + zend_spprintf(error, 0, "a valid path%s, %s given", + check_null ? " or null" : "", zend_zval_type_name(arg) + ); + return ""; } } break; @@ -674,7 +680,10 @@ static const char *zend_parse_arg_impl(int arg_num, zval *arg, va_list *va, cons { zend_string **str = va_arg(*va, zend_string **); if (!zend_parse_arg_path_str(arg, str, check_null)) { - return "a valid path"; + zend_spprintf(error, 0, "a valid path%s, %s given", + check_null ? " or null" : "", zend_zval_type_name(arg) + ); + return ""; } } break; @@ -683,7 +692,7 @@ static const char *zend_parse_arg_impl(int arg_num, zval *arg, va_list *va, cons { zend_string **str = va_arg(*va, zend_string **); if (!zend_parse_arg_str(arg, str, check_null)) { - return "string"; + return check_null ? "?string" : "string"; } } break; @@ -698,7 +707,7 @@ static const char *zend_parse_arg_impl(int arg_num, zval *arg, va_list *va, cons } if (!zend_parse_arg_bool(arg, p, is_null, check_null)) { - return "bool"; + return check_null ? "?bool" : "bool"; } } break; @@ -708,7 +717,7 @@ static const char *zend_parse_arg_impl(int arg_num, zval *arg, va_list *va, cons zval **p = va_arg(*va, zval **); if (!zend_parse_arg_resource(arg, p, check_null)) { - return "resource"; + return check_null ? "resource or null" : "resource"; } } break; @@ -719,7 +728,7 @@ static const char *zend_parse_arg_impl(int arg_num, zval *arg, va_list *va, cons zval **p = va_arg(*va, zval **); if (!zend_parse_arg_array(arg, p, check_null, c == 'A')) { - return "array"; + return check_null ? "?array" : "array"; } } break; @@ -730,7 +739,7 @@ static const char *zend_parse_arg_impl(int arg_num, zval *arg, va_list *va, cons HashTable **p = va_arg(*va, HashTable **); if (!zend_parse_arg_array_ht(arg, p, check_null, c == 'H', separate)) { - return "array"; + return check_null ? "?array" : "array"; } } break; @@ -740,7 +749,7 @@ static const char *zend_parse_arg_impl(int arg_num, zval *arg, va_list *va, cons zval **p = va_arg(*va, zval **); if (!zend_parse_arg_object(arg, p, NULL, check_null)) { - return "object"; + return check_null ? "?object" : "object"; } } break; @@ -752,9 +761,14 @@ static const char *zend_parse_arg_impl(int arg_num, zval *arg, va_list *va, cons if (!zend_parse_arg_object(arg, p, ce, check_null)) { if (ce) { - return ZSTR_VAL(ce->name); + if (check_null) { + zend_spprintf(error, 0, "of type ?%s, %s given", ZSTR_VAL(ce->name), zend_zval_type_name(arg)); + return ""; + } else { + return ZSTR_VAL(ce->name); + } } else { - return "object"; + return check_null ? "?object" : "object"; } } } @@ -771,7 +785,7 @@ static const char *zend_parse_arg_impl(int arg_num, zval *arg, va_list *va, cons } if (!try_convert_to_string(arg)) { *pce = NULL; - return "valid class name"; + return ""; /* try_convert_to_string() throws an exception */ } if ((lookup = zend_lookup_class(Z_STR_P(arg))) == NULL) { @@ -781,15 +795,15 @@ static const char *zend_parse_arg_impl(int arg_num, zval *arg, va_list *va, cons } if (ce_base) { if ((!*pce || !instanceof_function(*pce, ce_base))) { - zend_spprintf(error, 0, "to be a class name derived from %s, '%s' given", - ZSTR_VAL(ce_base->name), Z_STRVAL_P(arg)); + zend_spprintf(error, 0, "a class name derived from %s%s, %s given", + ZSTR_VAL(ce_base->name), check_null ? " or null" : "", Z_STRVAL_P(arg)); *pce = NULL; return ""; } } if (!*pce) { - zend_spprintf(error, 0, "to be a valid class name, '%s' given", - Z_STRVAL_P(arg)); + zend_spprintf(error, 0, "a valid class name%s, %s given", + check_null ? " or null" : "", Z_STRVAL_P(arg)); return ""; } break; @@ -810,23 +824,20 @@ static const char *zend_parse_arg_impl(int arg_num, zval *arg, va_list *va, cons } if (zend_fcall_info_init(arg, 0, fci, fcc, NULL, &is_callable_error) == SUCCESS) { - if (is_callable_error) { - *severity = E_DEPRECATED; - zend_spprintf(error, 0, "to be a valid callback, %s", is_callable_error); - efree(is_callable_error); - *spec = spec_walk; - return ""; - } + ZEND_ASSERT(!is_callable_error); + /* Release call trampolines: The function may not get called, in which case + * the trampoline will leak. Force it to be refetched during + * zend_call_function instead. */ + zend_release_fcall_info_cache(fcc); break; + } + + if (is_callable_error) { + zend_spprintf(error, 0, "a valid callback%s, %s", check_null ? " or null" : "", is_callable_error); + efree(is_callable_error); + return ""; } else { - if (is_callable_error) { - *severity = E_ERROR; - zend_spprintf(error, 0, "to be a valid callback, %s", is_callable_error); - efree(is_callable_error); - return ""; - } else { - return "valid callback"; - } + return check_null ? "a valid callback or null" : "a valid callback"; } } @@ -838,9 +849,9 @@ static const char *zend_parse_arg_impl(int arg_num, zval *arg, va_list *va, cons } break; - case 'Z': - /* 'Z' iz not supported anymore and should be replaced with 'z' */ - ZEND_ASSERT(c != 'Z'); + case 'Z': /* replace with 'z' */ + case 'L': /* replace with 'l' */ + ZEND_ASSERT(0 && "ZPP modifier no longer supported"); default: return "unknown"; } @@ -851,47 +862,38 @@ 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 flags) /* {{{ */ +static zend_result zend_parse_arg(uint32_t arg_num, zval *arg, va_list *va, const char **spec, int flags) /* {{{ */ { const char *expected_type = NULL; char *error = NULL; - int severity = 0; - expected_type = zend_parse_arg_impl(arg_num, arg, va, spec, &error, &severity); + expected_type = zend_parse_arg_impl(arg, va, spec, &error); if (expected_type) { if (EG(exception)) { return FAILURE; } if (!(flags & ZEND_PARSE_PARAMS_QUIET) && (*expected_type || error)) { - const char *space; - const char *class_name = get_active_class_name(&space); - zend_bool throw_exception = - ZEND_ARG_USES_STRICT_TYPES() || (flags & ZEND_PARSE_PARAMS_THROW); - if (error) { - zend_internal_type_error(throw_exception, "%s%s%s() expects parameter %d %s", - class_name, space, get_active_function_name(), arg_num, error); + zend_argument_type_error(arg_num, "must be %s", error); efree(error); } else { - zend_internal_type_error(throw_exception, - "%s%s%s() expects parameter %d to be %s, %s given", - class_name, space, get_active_function_name(), arg_num, expected_type, - zend_zval_type_name(arg)); + zend_argument_type_error(arg_num, "must be of type %s, %s given", expected_type, zend_zval_type_name(arg)); } + } else if (error) { + efree(error); } - if (severity != E_DEPRECATED) { - return FAILURE; - } + + return FAILURE; } return SUCCESS; } /* }}} */ -ZEND_API int zend_parse_parameter(int flags, int arg_num, zval *arg, const char *spec, ...) +ZEND_API zend_result zend_parse_parameter(int flags, uint32_t arg_num, zval *arg, const char *spec, ...) { va_list va; - int ret; + zend_result ret; va_start(va, spec); ret = zend_parse_arg(arg_num, arg, &va, &spec, flags); @@ -909,16 +911,17 @@ static ZEND_COLD void zend_parse_parameters_debug_error(const char *msg) { ZSTR_VAL(active_function->common.function_name), msg); } -static int zend_parse_va_args(int num_args, const char *type_spec, va_list *va, int flags) /* {{{ */ +static zend_result zend_parse_va_args(uint32_t num_args, const char *type_spec, va_list *va, int flags) /* {{{ */ { const char *spec_walk; - int c, i; - int min_num_args = -1; - int max_num_args = 0; - int post_varargs = 0; + char c; + uint32_t i; + uint32_t min_num_args = 0; + uint32_t max_num_args = 0; + uint32_t post_varargs = 0; zval *arg; - int arg_count; zend_bool have_varargs = 0; + zend_bool have_optional_args = 0; zval **varargs = NULL; int *n_varargs = NULL; @@ -934,12 +937,13 @@ static int zend_parse_va_args(int num_args, const char *type_spec, va_list *va, case 'f': case 'A': case 'H': case 'p': case 'S': case 'P': - case 'L': + case 'L': case 'n': max_num_args++; break; case '|': min_num_args = max_num_args; + have_optional_args = 1; break; case '/': @@ -961,6 +965,11 @@ static int zend_parse_va_args(int num_args, const char *type_spec, va_list *va, } /* mark the beginning of varargs */ post_varargs = max_num_args; + + if (ZEND_CALL_INFO(EG(current_execute_data)) & ZEND_CALL_HAS_EXTRA_NAMED_PARAMS) { + zend_unexpected_extra_named_error(); + return FAILURE; + } break; default: @@ -969,22 +978,22 @@ static int zend_parse_va_args(int num_args, const char *type_spec, va_list *va, } } - if (min_num_args < 0) { + /* with no optional arguments the minimum number of arguments must be the same as the maximum */ + if (!have_optional_args) { min_num_args = max_num_args; } if (have_varargs) { /* calculate how many required args are at the end of the specifier list */ post_varargs = max_num_args - post_varargs; - max_num_args = -1; + max_num_args = UINT32_MAX; } - if (num_args < min_num_args || (num_args > max_num_args && max_num_args >= 0)) { + if (num_args < min_num_args || num_args > max_num_args) { if (!(flags & ZEND_PARSE_PARAMS_QUIET)) { zend_function *active_function = EG(current_execute_data)->func; const char *class_name = active_function->common.scope ? ZSTR_VAL(active_function->common.scope->name) : ""; - zend_bool throw_exception = ZEND_ARG_USES_STRICT_TYPES() || (flags & ZEND_PARSE_PARAMS_THROW); - zend_internal_argument_count_error(throw_exception, "%s%s%s() expects %s %d parameter%s, %d given", + zend_argument_count_error("%s%s%s() expects %s %d parameter%s, %d given", class_name, class_name[0] ? "::" : "", ZSTR_VAL(active_function->common.function_name), @@ -996,9 +1005,7 @@ static int zend_parse_va_args(int num_args, const char *type_spec, va_list *va, return FAILURE; } - arg_count = ZEND_CALL_NUM_ARGS(EG(current_execute_data)); - - if (num_args > arg_count) { + if (num_args > ZEND_CALL_NUM_ARGS(EG(current_execute_data))) { zend_parse_parameters_debug_error("could not obtain parameters for parsing"); return FAILURE; } @@ -1046,10 +1053,10 @@ static int zend_parse_va_args(int num_args, const char *type_spec, va_list *va, } /* }}} */ -ZEND_API int zend_parse_parameters_ex(int flags, int num_args, const char *type_spec, ...) /* {{{ */ +ZEND_API zend_result zend_parse_parameters_ex(int flags, uint32_t num_args, const char *type_spec, ...) /* {{{ */ { va_list va; - int retval; + zend_result retval; va_start(va, type_spec); retval = zend_parse_va_args(num_args, type_spec, &va, flags); @@ -1059,10 +1066,10 @@ ZEND_API int zend_parse_parameters_ex(int flags, int num_args, const char *type_ } /* }}} */ -ZEND_API int zend_parse_parameters(int num_args, const char *type_spec, ...) /* {{{ */ +ZEND_API zend_result zend_parse_parameters(uint32_t num_args, const char *type_spec, ...) /* {{{ */ { va_list va; - int retval; + zend_result retval; int flags = 0; va_start(va, type_spec); @@ -1073,24 +1080,10 @@ ZEND_API int zend_parse_parameters(int num_args, const char *type_spec, ...) /* } /* }}} */ -ZEND_API int zend_parse_parameters_throw(int num_args, const char *type_spec, ...) /* {{{ */ +ZEND_API zend_result zend_parse_method_parameters(uint32_t num_args, zval *this_ptr, const char *type_spec, ...) /* {{{ */ { va_list va; - int retval; - int flags = ZEND_PARSE_PARAMS_THROW; - - va_start(va, type_spec); - retval = zend_parse_va_args(num_args, type_spec, &va, flags); - va_end(va); - - return retval; -} -/* }}} */ - -ZEND_API int zend_parse_method_parameters(int num_args, zval *this_ptr, const char *type_spec, ...) /* {{{ */ -{ - va_list va; - int retval; + zend_result retval; int flags = 0; const char *p = type_spec; zval **object; @@ -1116,7 +1109,7 @@ ZEND_API int zend_parse_method_parameters(int num_args, zval *this_ptr, const ch *object = this_ptr; if (ce && !instanceof_function(Z_OBJCE_P(this_ptr), ce)) { - zend_error_noreturn(E_CORE_ERROR, "%s::%s() must be derived from %s::%s", + zend_error_noreturn(E_CORE_ERROR, "%s::%s() must be derived from %s::%s()", ZSTR_VAL(Z_OBJCE_P(this_ptr)->name), get_active_function_name(), ZSTR_VAL(ce->name), get_active_function_name()); } @@ -1127,10 +1120,10 @@ ZEND_API int zend_parse_method_parameters(int num_args, zval *this_ptr, const ch } /* }}} */ -ZEND_API int zend_parse_method_parameters_ex(int flags, int num_args, zval *this_ptr, const char *type_spec, ...) /* {{{ */ +ZEND_API zend_result zend_parse_method_parameters_ex(int flags, uint32_t num_args, zval *this_ptr, const char *type_spec, ...) /* {{{ */ { va_list va; - int retval; + zend_result retval; const char *p = type_spec; zval **object; zend_class_entry *ce; @@ -1149,7 +1142,7 @@ ZEND_API int zend_parse_method_parameters_ex(int flags, int num_args, zval *this if (ce && !instanceof_function(Z_OBJCE_P(this_ptr), ce)) { if (!(flags & ZEND_PARSE_PARAMS_QUIET)) { - zend_error_noreturn(E_CORE_ERROR, "%s::%s() must be derived from %s::%s", + zend_error_noreturn(E_CORE_ERROR, "%s::%s() must be derived from %s::%s()", ZSTR_VAL(ce->name), get_active_function_name(), ZSTR_VAL(Z_OBJCE_P(this_ptr)->name), get_active_function_name()); } va_end(va); @@ -1167,7 +1160,8 @@ ZEND_API int zend_parse_method_parameters_ex(int flags, int num_args, zval *this * because it may call __set from the uninitialized object otherwise. */ ZEND_API void zend_merge_properties(zval *obj, HashTable *properties) /* {{{ */ { - const zend_object_handlers *obj_ht = Z_OBJ_HT_P(obj); + zend_object *zobj = Z_OBJ_P(obj); + zend_object_write_property_t write_property = zobj->handlers->write_property; zend_class_entry *old_scope = EG(fake_scope); zend_string *key; zval *value; @@ -1175,20 +1169,16 @@ ZEND_API void zend_merge_properties(zval *obj, HashTable *properties) /* {{{ */ EG(fake_scope) = Z_OBJCE_P(obj); ZEND_HASH_FOREACH_STR_KEY_VAL(properties, key, value) { if (key) { - zval member; - - ZVAL_STR(&member, key); - obj_ht->write_property(obj, &member, value, NULL); + write_property(zobj, key, value, NULL); } } ZEND_HASH_FOREACH_END(); EG(fake_scope) = old_scope; } /* }}} */ -ZEND_API int zend_update_class_constants(zend_class_entry *class_type) /* {{{ */ +ZEND_API zend_result zend_update_class_constants(zend_class_entry *class_type) /* {{{ */ { if (!(class_type->ce_flags & ZEND_ACC_CONSTANTS_UPDATED)) { - zend_class_entry *ce; zend_class_constant *c; zval *val; zend_property_info *prop_info; @@ -1214,39 +1204,33 @@ ZEND_API int zend_update_class_constants(zend_class_entry *class_type) /* {{{ */ } } - ce = class_type; - while (ce) { - ZEND_HASH_FOREACH_PTR(&ce->properties_info, prop_info) { - if (prop_info->ce == ce) { - if (prop_info->flags & ZEND_ACC_STATIC) { - val = CE_STATIC_MEMBERS(class_type) + prop_info->offset; - } else { - val = (zval*)((char*)class_type->default_properties_table + prop_info->offset - OBJ_PROP_TO_OFFSET(0)); + ZEND_HASH_FOREACH_PTR(&class_type->properties_info, prop_info) { + if (prop_info->flags & ZEND_ACC_STATIC) { + val = CE_STATIC_MEMBERS(class_type) + prop_info->offset; + } else { + val = (zval*)((char*)class_type->default_properties_table + prop_info->offset - OBJ_PROP_TO_OFFSET(0)); + } + if (Z_TYPE_P(val) == IS_CONSTANT_AST) { + if (ZEND_TYPE_IS_SET(prop_info->type)) { + zval tmp; + + ZVAL_COPY(&tmp, val); + if (UNEXPECTED(zval_update_constant_ex(&tmp, prop_info->ce) != SUCCESS)) { + zval_ptr_dtor(&tmp); + return FAILURE; } - if (Z_TYPE_P(val) == IS_CONSTANT_AST) { - if (prop_info->type) { - zval tmp; - - ZVAL_COPY(&tmp, val); - if (UNEXPECTED(zval_update_constant_ex(&tmp, ce) != SUCCESS)) { - zval_ptr_dtor(&tmp); - return FAILURE; - } - /* property initializers must always be evaluated with strict types */; - if (UNEXPECTED(!zend_verify_property_type(prop_info, &tmp, /* strict */ 1))) { - zval_ptr_dtor(&tmp); - return FAILURE; - } - zval_ptr_dtor(val); - ZVAL_COPY_VALUE(val, &tmp); - } else if (UNEXPECTED(zval_update_constant_ex(val, ce) != SUCCESS)) { - return FAILURE; - } + /* property initializers must always be evaluated with strict types */; + if (UNEXPECTED(!zend_verify_property_type(prop_info, &tmp, /* strict */ 1))) { + zval_ptr_dtor(&tmp); + return FAILURE; } + zval_ptr_dtor(val); + ZVAL_COPY_VALUE(val, &tmp); + } else if (UNEXPECTED(zval_update_constant_ex(val, prop_info->ce) != SUCCESS)) { + return FAILURE; } - } ZEND_HASH_FOREACH_END(); - ce = ce->parent; - } + } + } ZEND_HASH_FOREACH_END(); class_type->ce_flags |= ZEND_ACC_CONSTANTS_UPDATED; } @@ -1301,7 +1285,7 @@ ZEND_API void object_properties_init_ex(zend_object *object, HashTable *properti (property_info->flags & ZEND_ACC_STATIC) == 0) { zval *slot = OBJ_PROP(object, property_info->offset); - if (UNEXPECTED(property_info->type)) { + if (UNEXPECTED(ZEND_TYPE_IS_SET(property_info->type))) { zval tmp; ZVAL_COPY_VALUE(&tmp, prop); @@ -1381,7 +1365,7 @@ ZEND_API void object_properties_load(zend_object *object, HashTable *properties) * class and all props being public. If only a subset is given or the class * has protected members then you need to merge the properties separately by * calling zend_merge_properties(). */ -static zend_always_inline int _object_and_properties_init(zval *arg, zend_class_entry *class_type, HashTable *properties) /* {{{ */ +static zend_always_inline zend_result _object_and_properties_init(zval *arg, zend_class_entry *class_type, HashTable *properties) /* {{{ */ { if (UNEXPECTED(class_type->ce_flags & (ZEND_ACC_INTERFACE|ZEND_ACC_TRAIT|ZEND_ACC_IMPLICIT_ABSTRACT_CLASS|ZEND_ACC_EXPLICIT_ABSTRACT_CLASS))) { if (class_type->ce_flags & ZEND_ACC_INTERFACE) { @@ -1420,193 +1404,175 @@ static zend_always_inline int _object_and_properties_init(zval *arg, zend_class_ } /* }}} */ -ZEND_API int object_and_properties_init(zval *arg, zend_class_entry *class_type, HashTable *properties) /* {{{ */ +ZEND_API zend_result object_and_properties_init(zval *arg, zend_class_entry *class_type, HashTable *properties) /* {{{ */ { return _object_and_properties_init(arg, class_type, properties); } /* }}} */ -ZEND_API int object_init_ex(zval *arg, zend_class_entry *class_type) /* {{{ */ +ZEND_API zend_result object_init_ex(zval *arg, zend_class_entry *class_type) /* {{{ */ { return _object_and_properties_init(arg, class_type, NULL); } /* }}} */ -ZEND_API int object_init(zval *arg) /* {{{ */ +ZEND_API void object_init(zval *arg) /* {{{ */ { ZVAL_OBJ(arg, zend_objects_new(zend_standard_class_def)); - return SUCCESS; } /* }}} */ -ZEND_API int add_assoc_long_ex(zval *arg, const char *key, size_t key_len, zend_long n) /* {{{ */ +ZEND_API void add_assoc_long_ex(zval *arg, const char *key, size_t key_len, zend_long n) /* {{{ */ { zval tmp; ZVAL_LONG(&tmp, n); zend_symtable_str_update(Z_ARRVAL_P(arg), key, key_len, &tmp); - return SUCCESS; } /* }}} */ -ZEND_API int add_assoc_null_ex(zval *arg, const char *key, size_t key_len) /* {{{ */ +ZEND_API void add_assoc_null_ex(zval *arg, const char *key, size_t key_len) /* {{{ */ { zval tmp; ZVAL_NULL(&tmp); zend_symtable_str_update(Z_ARRVAL_P(arg), key, key_len, &tmp); - return SUCCESS; } /* }}} */ -ZEND_API int add_assoc_bool_ex(zval *arg, const char *key, size_t key_len, int b) /* {{{ */ +ZEND_API void add_assoc_bool_ex(zval *arg, const char *key, size_t key_len, bool b) /* {{{ */ { zval tmp; ZVAL_BOOL(&tmp, b); zend_symtable_str_update(Z_ARRVAL_P(arg), key, key_len, &tmp); - return SUCCESS; } /* }}} */ -ZEND_API int add_assoc_resource_ex(zval *arg, const char *key, size_t key_len, zend_resource *r) /* {{{ */ +ZEND_API void add_assoc_resource_ex(zval *arg, const char *key, size_t key_len, zend_resource *r) /* {{{ */ { zval tmp; ZVAL_RES(&tmp, r); zend_symtable_str_update(Z_ARRVAL_P(arg), key, key_len, &tmp); - return SUCCESS; } /* }}} */ -ZEND_API int add_assoc_double_ex(zval *arg, const char *key, size_t key_len, double d) /* {{{ */ +ZEND_API void add_assoc_double_ex(zval *arg, const char *key, size_t key_len, double d) /* {{{ */ { zval tmp; ZVAL_DOUBLE(&tmp, d); zend_symtable_str_update(Z_ARRVAL_P(arg), key, key_len, &tmp); - return SUCCESS; } /* }}} */ -ZEND_API int add_assoc_str_ex(zval *arg, const char *key, size_t key_len, zend_string *str) /* {{{ */ +ZEND_API void add_assoc_str_ex(zval *arg, const char *key, size_t key_len, zend_string *str) /* {{{ */ { zval tmp; ZVAL_STR(&tmp, str); zend_symtable_str_update(Z_ARRVAL_P(arg), key, key_len, &tmp); - return SUCCESS; } /* }}} */ -ZEND_API int add_assoc_string_ex(zval *arg, const char *key, size_t key_len, const char *str) /* {{{ */ +ZEND_API void add_assoc_string_ex(zval *arg, const char *key, size_t key_len, const char *str) /* {{{ */ { zval tmp; ZVAL_STRING(&tmp, str); zend_symtable_str_update(Z_ARRVAL_P(arg), key, key_len, &tmp); - return SUCCESS; } /* }}} */ -ZEND_API int add_assoc_stringl_ex(zval *arg, const char *key, size_t key_len, const char *str, size_t length) /* {{{ */ +ZEND_API void add_assoc_stringl_ex(zval *arg, const char *key, size_t key_len, const char *str, size_t length) /* {{{ */ { zval tmp; ZVAL_STRINGL(&tmp, str, length); zend_symtable_str_update(Z_ARRVAL_P(arg), key, key_len, &tmp); - return SUCCESS; } /* }}} */ -ZEND_API int add_assoc_zval_ex(zval *arg, const char *key, size_t key_len, zval *value) /* {{{ */ +ZEND_API void add_assoc_zval_ex(zval *arg, const char *key, size_t key_len, zval *value) /* {{{ */ { zend_symtable_str_update(Z_ARRVAL_P(arg), key, key_len, value); - return SUCCESS; } /* }}} */ -ZEND_API int add_index_long(zval *arg, zend_ulong index, zend_long n) /* {{{ */ +ZEND_API void add_index_long(zval *arg, zend_ulong index, zend_long n) /* {{{ */ { zval tmp; ZVAL_LONG(&tmp, n); zend_hash_index_update(Z_ARRVAL_P(arg), index, &tmp); - return SUCCESS; } /* }}} */ -ZEND_API int add_index_null(zval *arg, zend_ulong index) /* {{{ */ +ZEND_API void add_index_null(zval *arg, zend_ulong index) /* {{{ */ { zval tmp; ZVAL_NULL(&tmp); zend_hash_index_update(Z_ARRVAL_P(arg), index, &tmp); - return SUCCESS; } /* }}} */ -ZEND_API int add_index_bool(zval *arg, zend_ulong index, int b) /* {{{ */ +ZEND_API void add_index_bool(zval *arg, zend_ulong index, bool b) /* {{{ */ { zval tmp; ZVAL_BOOL(&tmp, b); zend_hash_index_update(Z_ARRVAL_P(arg), index, &tmp); - return SUCCESS; } /* }}} */ -ZEND_API int add_index_resource(zval *arg, zend_ulong index, zend_resource *r) /* {{{ */ +ZEND_API void add_index_resource(zval *arg, zend_ulong index, zend_resource *r) /* {{{ */ { zval tmp; ZVAL_RES(&tmp, r); zend_hash_index_update(Z_ARRVAL_P(arg), index, &tmp); - return SUCCESS; } /* }}} */ -ZEND_API int add_index_double(zval *arg, zend_ulong index, double d) /* {{{ */ +ZEND_API void add_index_double(zval *arg, zend_ulong index, double d) /* {{{ */ { zval tmp; ZVAL_DOUBLE(&tmp, d); zend_hash_index_update(Z_ARRVAL_P(arg), index, &tmp); - return SUCCESS; } /* }}} */ -ZEND_API int add_index_str(zval *arg, zend_ulong index, zend_string *str) /* {{{ */ +ZEND_API void add_index_str(zval *arg, zend_ulong index, zend_string *str) /* {{{ */ { zval tmp; ZVAL_STR(&tmp, str); zend_hash_index_update(Z_ARRVAL_P(arg), index, &tmp); - return SUCCESS; } /* }}} */ -ZEND_API int add_index_string(zval *arg, zend_ulong index, const char *str) /* {{{ */ +ZEND_API void add_index_string(zval *arg, zend_ulong index, const char *str) /* {{{ */ { zval tmp; ZVAL_STRING(&tmp, str); zend_hash_index_update(Z_ARRVAL_P(arg), index, &tmp); - return SUCCESS; } /* }}} */ -ZEND_API int add_index_stringl(zval *arg, zend_ulong index, const char *str, size_t length) /* {{{ */ +ZEND_API void add_index_stringl(zval *arg, zend_ulong index, const char *str, size_t length) /* {{{ */ { zval tmp; ZVAL_STRINGL(&tmp, str, length); zend_hash_index_update(Z_ARRVAL_P(arg), index, &tmp); - return SUCCESS; } /* }}} */ -ZEND_API int add_next_index_long(zval *arg, zend_long n) /* {{{ */ +ZEND_API zend_result add_next_index_long(zval *arg, zend_long n) /* {{{ */ { zval tmp; @@ -1615,7 +1581,7 @@ ZEND_API int add_next_index_long(zval *arg, zend_long n) /* {{{ */ } /* }}} */ -ZEND_API int add_next_index_null(zval *arg) /* {{{ */ +ZEND_API zend_result add_next_index_null(zval *arg) /* {{{ */ { zval tmp; @@ -1624,7 +1590,7 @@ ZEND_API int add_next_index_null(zval *arg) /* {{{ */ } /* }}} */ -ZEND_API int add_next_index_bool(zval *arg, int b) /* {{{ */ +ZEND_API zend_result add_next_index_bool(zval *arg, zend_bool b) /* {{{ */ { zval tmp; @@ -1633,7 +1599,7 @@ ZEND_API int add_next_index_bool(zval *arg, int b) /* {{{ */ } /* }}} */ -ZEND_API int add_next_index_resource(zval *arg, zend_resource *r) /* {{{ */ +ZEND_API zend_result add_next_index_resource(zval *arg, zend_resource *r) /* {{{ */ { zval tmp; @@ -1642,7 +1608,7 @@ ZEND_API int add_next_index_resource(zval *arg, zend_resource *r) /* {{{ */ } /* }}} */ -ZEND_API int add_next_index_double(zval *arg, double d) /* {{{ */ +ZEND_API zend_result add_next_index_double(zval *arg, double d) /* {{{ */ { zval tmp; @@ -1651,7 +1617,7 @@ ZEND_API int add_next_index_double(zval *arg, double d) /* {{{ */ } /* }}} */ -ZEND_API int add_next_index_str(zval *arg, zend_string *str) /* {{{ */ +ZEND_API zend_result add_next_index_str(zval *arg, zend_string *str) /* {{{ */ { zval tmp; @@ -1660,7 +1626,7 @@ ZEND_API int add_next_index_str(zval *arg, zend_string *str) /* {{{ */ } /* }}} */ -ZEND_API int add_next_index_string(zval *arg, const char *str) /* {{{ */ +ZEND_API zend_result add_next_index_string(zval *arg, const char *str) /* {{{ */ { zval tmp; @@ -1669,7 +1635,7 @@ ZEND_API int add_next_index_string(zval *arg, const char *str) /* {{{ */ } /* }}} */ -ZEND_API int add_next_index_stringl(zval *arg, const char *str, size_t length) /* {{{ */ +ZEND_API zend_result add_next_index_stringl(zval *arg, const char *str, size_t length) /* {{{ */ { zval tmp; @@ -1678,7 +1644,7 @@ ZEND_API int add_next_index_stringl(zval *arg, const char *str, size_t length) / } /* }}} */ -ZEND_API int array_set_zval_key(HashTable *ht, zval *key, zval *value) /* {{{ */ +ZEND_API zend_result array_set_zval_key(HashTable *ht, zval *key, zval *value) /* {{{ */ { zval *result; @@ -1687,10 +1653,10 @@ ZEND_API int array_set_zval_key(HashTable *ht, zval *key, zval *value) /* {{{ */ result = zend_symtable_update(ht, Z_STR_P(key), value); break; case IS_NULL: - result = zend_symtable_update(ht, ZSTR_EMPTY_ALLOC(), value); + result = zend_hash_update(ht, ZSTR_EMPTY_ALLOC(), value); break; case IS_RESOURCE: - zend_error(E_NOTICE, "Resource ID#%d used as offset, casting to integer (%d)", Z_RES_HANDLE_P(key), Z_RES_HANDLE_P(key)); + zend_error(E_WARNING, "Resource ID#%d used as offset, casting to integer (%d)", Z_RES_HANDLE_P(key), Z_RES_HANDLE_P(key)); result = zend_hash_index_update(ht, Z_RES_HANDLE_P(key), value); break; case IS_FALSE: @@ -1706,7 +1672,7 @@ ZEND_API int array_set_zval_key(HashTable *ht, zval *key, zval *value) /* {{{ */ result = zend_hash_index_update(ht, zend_dval_to_lval(Z_DVAL_P(key)), value); break; default: - zend_error(E_WARNING, "Illegal offset type"); + zend_type_error("Illegal offset type"); result = NULL; } @@ -1719,98 +1685,93 @@ ZEND_API int array_set_zval_key(HashTable *ht, zval *key, zval *value) /* {{{ */ } /* }}} */ -ZEND_API int add_property_long_ex(zval *arg, const char *key, size_t key_len, zend_long n) /* {{{ */ +ZEND_API void add_property_long_ex(zval *arg, const char *key, size_t key_len, zend_long n) /* {{{ */ { zval tmp; ZVAL_LONG(&tmp, n); - return add_property_zval_ex(arg, key, key_len, &tmp); + add_property_zval_ex(arg, key, key_len, &tmp); } /* }}} */ -ZEND_API int add_property_bool_ex(zval *arg, const char *key, size_t key_len, zend_long b) /* {{{ */ +ZEND_API void add_property_bool_ex(zval *arg, const char *key, size_t key_len, zend_long b) /* {{{ */ { zval tmp; ZVAL_BOOL(&tmp, b); - return add_property_zval_ex(arg, key, key_len, &tmp); + add_property_zval_ex(arg, key, key_len, &tmp); } /* }}} */ -ZEND_API int add_property_null_ex(zval *arg, const char *key, size_t key_len) /* {{{ */ +ZEND_API void add_property_null_ex(zval *arg, const char *key, size_t key_len) /* {{{ */ { zval tmp; ZVAL_NULL(&tmp); - return add_property_zval_ex(arg, key, key_len, &tmp); + add_property_zval_ex(arg, key, key_len, &tmp); } /* }}} */ -ZEND_API int add_property_resource_ex(zval *arg, const char *key, size_t key_len, zend_resource *r) /* {{{ */ +ZEND_API void add_property_resource_ex(zval *arg, const char *key, size_t key_len, zend_resource *r) /* {{{ */ { zval tmp; ZVAL_RES(&tmp, r); add_property_zval_ex(arg, key, key_len, &tmp); zval_ptr_dtor(&tmp); /* write_property will add 1 to refcount */ - return SUCCESS; } /* }}} */ -ZEND_API int add_property_double_ex(zval *arg, const char *key, size_t key_len, double d) /* {{{ */ +ZEND_API void add_property_double_ex(zval *arg, const char *key, size_t key_len, double d) /* {{{ */ { zval tmp; ZVAL_DOUBLE(&tmp, d); - return add_property_zval_ex(arg, key, key_len, &tmp); + add_property_zval_ex(arg, key, key_len, &tmp); } /* }}} */ -ZEND_API int add_property_str_ex(zval *arg, const char *key, size_t key_len, zend_string *str) /* {{{ */ +ZEND_API void add_property_str_ex(zval *arg, const char *key, size_t key_len, zend_string *str) /* {{{ */ { zval tmp; ZVAL_STR(&tmp, str); add_property_zval_ex(arg, key, key_len, &tmp); zval_ptr_dtor(&tmp); /* write_property will add 1 to refcount */ - return SUCCESS; } /* }}} */ -ZEND_API int add_property_string_ex(zval *arg, const char *key, size_t key_len, const char *str) /* {{{ */ +ZEND_API void add_property_string_ex(zval *arg, const char *key, size_t key_len, const char *str) /* {{{ */ { zval tmp; ZVAL_STRING(&tmp, str); add_property_zval_ex(arg, key, key_len, &tmp); zval_ptr_dtor(&tmp); /* write_property will add 1 to refcount */ - return SUCCESS; } /* }}} */ -ZEND_API int add_property_stringl_ex(zval *arg, const char *key, size_t key_len, const char *str, size_t length) /* {{{ */ +ZEND_API void add_property_stringl_ex(zval *arg, const char *key, size_t key_len, const char *str, size_t length) /* {{{ */ { zval tmp; ZVAL_STRINGL(&tmp, str, length); add_property_zval_ex(arg, key, key_len, &tmp); zval_ptr_dtor(&tmp); /* write_property will add 1 to refcount */ - return SUCCESS; } /* }}} */ -ZEND_API int add_property_zval_ex(zval *arg, const char *key, size_t key_len, zval *value) /* {{{ */ +ZEND_API void add_property_zval_ex(zval *arg, const char *key, size_t key_len, zval *value) /* {{{ */ { - zval z_key; + zend_string *str; - ZVAL_STRINGL(&z_key, key, key_len); - Z_OBJ_HANDLER_P(arg, write_property)(arg, &z_key, value, NULL); - zval_ptr_dtor(&z_key); - return SUCCESS; + str = zend_string_init(key, key_len, 0); + Z_OBJ_HANDLER_P(arg, write_property)(Z_OBJ_P(arg), str, value, NULL); + zend_string_release_ex(str, 0); } /* }}} */ -ZEND_API int zend_startup_module_ex(zend_module_entry *module) /* {{{ */ +ZEND_API zend_result zend_startup_module_ex(zend_module_entry *module) /* {{{ */ { size_t name_len; zend_string *lcname; @@ -1835,7 +1796,7 @@ ZEND_API int zend_startup_module_ex(zend_module_entry *module) /* {{{ */ if ((req_mod = zend_hash_find_ptr(&module_registry, lcname)) == NULL || !req_mod->module_started) { zend_string_efree(lcname); /* TODO: Check version relationship */ - zend_error(E_CORE_WARNING, "Cannot load module '%s' because required module '%s' is not loaded", module->name, dep->name); + zend_error(E_CORE_WARNING, "Cannot load module \"%s\" because required module \"%s\" is not loaded", module->name, dep->name); module->module_started = 0; return FAILURE; } @@ -1980,11 +1941,10 @@ ZEND_API void zend_collect_module_handlers(void) /* {{{ */ } /* }}} */ -ZEND_API int zend_startup_modules(void) /* {{{ */ +ZEND_API void zend_startup_modules(void) /* {{{ */ { zend_hash_sort_ex(&module_registry, zend_sort_modules, NULL, 0); zend_hash_apply(&module_registry, zend_startup_module_zval); - return SUCCESS; } /* }}} */ @@ -2023,7 +1983,7 @@ ZEND_API zend_module_entry* zend_register_module_ex(zend_module_entry *module) / if (zend_hash_exists(&module_registry, lcname) || zend_get_extension(dep->name)) { zend_string_efree(lcname); /* TODO: Check version relationship */ - zend_error(E_CORE_WARNING, "Cannot load module '%s' because conflicting module '%s' is already loaded", module->name, dep->name); + zend_error(E_CORE_WARNING, "Cannot load module \"%s\" because conflicting module \"%s\" is already loaded", module->name, dep->name); return NULL; } zend_string_efree(lcname); @@ -2038,7 +1998,7 @@ ZEND_API zend_module_entry* zend_register_module_ex(zend_module_entry *module) / lcname = zend_new_interned_string(lcname); if ((module_ptr = zend_hash_add_mem(&module_registry, lcname, module, sizeof(zend_module_entry))) == NULL) { - zend_error(E_CORE_WARNING, "Module '%s' already loaded", module->name); + zend_error(E_CORE_WARNING, "Module \"%s\" is already loaded", module->name); zend_string_release(lcname); return NULL; } @@ -2067,77 +2027,238 @@ ZEND_API zend_module_entry* zend_register_internal_module(zend_module_entry *mod } /* }}} */ -ZEND_API void zend_check_magic_method_implementation(const zend_class_entry *ce, const zend_function *fptr, int error_type) /* {{{ */ +static void zend_check_magic_method_args( + uint32_t num_args, const zend_class_entry *ce, const zend_function *fptr, int error_type) { - char lcname[16]; - size_t name_len; + if (fptr->common.num_args != num_args) { + if (num_args == 0) { + zend_error(error_type, "Method %s::%s() cannot take arguments", + ZSTR_VAL(ce->name), ZSTR_VAL(fptr->common.function_name)); + } else if (num_args == 1) { + zend_error(error_type, "Method %s::%s() must take exactly 1 argument", + ZSTR_VAL(ce->name), ZSTR_VAL(fptr->common.function_name)); + } else { + zend_error(error_type, "Method %s::%s() must take exactly %" PRIu32 " arguments", + ZSTR_VAL(ce->name), ZSTR_VAL(fptr->common.function_name), num_args); + } + return; + } + for (uint32_t i = 0; i < num_args; i++) { + if (QUICK_ARG_SHOULD_BE_SENT_BY_REF(fptr, i + 1)) { + zend_error(error_type, "Method %s::%s() cannot take arguments by reference", + ZSTR_VAL(ce->name), ZSTR_VAL(fptr->common.function_name)); + return; + } + } +} + +static void zend_check_magic_method_arg_type(uint32_t arg_num, const zend_class_entry *ce, const zend_function *fptr, int error_type, int arg_type) +{ + if ( + ZEND_TYPE_IS_SET(fptr->common.arg_info[arg_num].type) + && !(ZEND_TYPE_FULL_MASK(fptr->common.arg_info[arg_num].type) & arg_type) + ) { + zend_error(error_type, "%s::%s(): Parameter #%d ($%s) must be of type %s when declared", + ZSTR_VAL(ce->name), ZSTR_VAL(fptr->common.function_name), + arg_num + 1, ZSTR_VAL(fptr->common.arg_info[arg_num].name), + ZSTR_VAL(zend_type_to_string((zend_type) ZEND_TYPE_INIT_MASK(arg_type)))); + } +} + +static void zend_check_magic_method_return_type(const zend_class_entry *ce, const zend_function *fptr, int error_type, int return_type) +{ + if (!(fptr->common.fn_flags & ZEND_ACC_HAS_RETURN_TYPE)) { + /* For backwards compatibility reasons, do not enforce the return type if it is not set. */ + return; + } + + bool has_class_type = ZEND_TYPE_HAS_CLASS(fptr->common.arg_info[-1].type); + uint32_t extra_types = ZEND_TYPE_PURE_MASK(fptr->common.arg_info[-1].type) & ~return_type; + if (extra_types & MAY_BE_STATIC) { + extra_types &= ~MAY_BE_STATIC; + has_class_type = 1; + } + + if (extra_types || (has_class_type && return_type != MAY_BE_OBJECT)) { + zend_error(error_type, "%s::%s(): Return type must be %s when declared", + ZSTR_VAL(ce->name), ZSTR_VAL(fptr->common.function_name), + ZSTR_VAL(zend_type_to_string((zend_type) ZEND_TYPE_INIT_MASK(return_type)))); + } +} + +static void zend_check_magic_method_non_static( + const zend_class_entry *ce, const zend_function *fptr, int error_type) +{ + if (fptr->common.fn_flags & ZEND_ACC_STATIC) { + zend_error(error_type, "Method %s::%s() cannot be static", + ZSTR_VAL(ce->name), ZSTR_VAL(fptr->common.function_name)); + } +} + +static void zend_check_magic_method_static( + const zend_class_entry *ce, const zend_function *fptr, int error_type) +{ + if (!(fptr->common.fn_flags & ZEND_ACC_STATIC)) { + zend_error(error_type, "Method %s::%s() must be static", + ZSTR_VAL(ce->name), ZSTR_VAL(fptr->common.function_name)); + } +} +static void zend_check_magic_method_public( + const zend_class_entry *ce, const zend_function *fptr, int error_type) +{ + // TODO: Remove this warning after adding proper visibility handling. + if (!(fptr->common.fn_flags & ZEND_ACC_PUBLIC)) { + zend_error(E_WARNING, "The magic method %s::%s() must have public visibility", + ZSTR_VAL(ce->name), ZSTR_VAL(fptr->common.function_name)); + } +} + +static void zend_check_magic_method_no_return_type( + const zend_class_entry *ce, const zend_function *fptr, int error_type) +{ + if (fptr->common.fn_flags & ZEND_ACC_HAS_RETURN_TYPE) { + zend_error_noreturn(error_type, "Method %s::%s() cannot declare a return type", + ZSTR_VAL(ce->name), ZSTR_VAL(fptr->common.function_name)); + } +} + +ZEND_API void zend_check_magic_method_implementation(const zend_class_entry *ce, const zend_function *fptr, zend_string *lcname, int error_type) /* {{{ */ +{ if (ZSTR_VAL(fptr->common.function_name)[0] != '_' || ZSTR_VAL(fptr->common.function_name)[1] != '_') { return; } - /* we don't care if the function name is longer, in fact lowercasing only - * the beginning of the name speeds up the check process */ - name_len = ZSTR_LEN(fptr->common.function_name); - zend_str_tolower_copy(lcname, ZSTR_VAL(fptr->common.function_name), MIN(name_len, sizeof(lcname)-1)); - lcname[sizeof(lcname)-1] = '\0'; /* zend_str_tolower_copy won't necessarily set the zero byte */ - - if (name_len == sizeof(ZEND_DESTRUCTOR_FUNC_NAME) - 1 && !memcmp(lcname, ZEND_DESTRUCTOR_FUNC_NAME, sizeof(ZEND_DESTRUCTOR_FUNC_NAME) - 1) && fptr->common.num_args != 0) { - zend_error(error_type, "Destructor %s::%s() cannot take arguments", ZSTR_VAL(ce->name), ZEND_DESTRUCTOR_FUNC_NAME); - } else if (name_len == sizeof(ZEND_CLONE_FUNC_NAME) - 1 && !memcmp(lcname, ZEND_CLONE_FUNC_NAME, sizeof(ZEND_CLONE_FUNC_NAME) - 1) && fptr->common.num_args != 0) { - zend_error(error_type, "Method %s::%s() cannot accept any arguments", ZSTR_VAL(ce->name), ZEND_CLONE_FUNC_NAME); - } else if (name_len == sizeof(ZEND_GET_FUNC_NAME) - 1 && !memcmp(lcname, ZEND_GET_FUNC_NAME, sizeof(ZEND_GET_FUNC_NAME) - 1)) { - if (fptr->common.num_args != 1) { - zend_error(error_type, "Method %s::%s() must take exactly 1 argument", ZSTR_VAL(ce->name), ZEND_GET_FUNC_NAME); - } else if (QUICK_ARG_SHOULD_BE_SENT_BY_REF(fptr, 1)) { - zend_error(error_type, "Method %s::%s() cannot take arguments by reference", ZSTR_VAL(ce->name), ZEND_GET_FUNC_NAME); - } - } else if (name_len == sizeof(ZEND_SET_FUNC_NAME) - 1 && !memcmp(lcname, ZEND_SET_FUNC_NAME, sizeof(ZEND_SET_FUNC_NAME) - 1)) { - if (fptr->common.num_args != 2) { - zend_error(error_type, "Method %s::%s() must take exactly 2 arguments", ZSTR_VAL(ce->name), ZEND_SET_FUNC_NAME); - } else if (QUICK_ARG_SHOULD_BE_SENT_BY_REF(fptr, 1) || QUICK_ARG_SHOULD_BE_SENT_BY_REF(fptr, 2)) { - zend_error(error_type, "Method %s::%s() cannot take arguments by reference", ZSTR_VAL(ce->name), ZEND_SET_FUNC_NAME); - } - } else if (name_len == sizeof(ZEND_UNSET_FUNC_NAME) - 1 && !memcmp(lcname, ZEND_UNSET_FUNC_NAME, sizeof(ZEND_UNSET_FUNC_NAME) - 1)) { - if (fptr->common.num_args != 1) { - zend_error(error_type, "Method %s::%s() must take exactly 1 argument", ZSTR_VAL(ce->name), ZEND_UNSET_FUNC_NAME); - } else if (QUICK_ARG_SHOULD_BE_SENT_BY_REF(fptr, 1)) { - zend_error(error_type, "Method %s::%s() cannot take arguments by reference", ZSTR_VAL(ce->name), ZEND_UNSET_FUNC_NAME); - } - } else if (name_len == sizeof(ZEND_ISSET_FUNC_NAME) - 1 && !memcmp(lcname, ZEND_ISSET_FUNC_NAME, sizeof(ZEND_ISSET_FUNC_NAME) - 1)) { - if (fptr->common.num_args != 1) { - zend_error(error_type, "Method %s::%s() must take exactly 1 argument", ZSTR_VAL(ce->name), ZEND_ISSET_FUNC_NAME); - } else if (QUICK_ARG_SHOULD_BE_SENT_BY_REF(fptr, 1)) { - zend_error(error_type, "Method %s::%s() cannot take arguments by reference", ZSTR_VAL(ce->name), ZEND_ISSET_FUNC_NAME); - } - } else if (name_len == sizeof(ZEND_CALL_FUNC_NAME) - 1 && !memcmp(lcname, ZEND_CALL_FUNC_NAME, sizeof(ZEND_CALL_FUNC_NAME) - 1)) { - if (fptr->common.num_args != 2) { - zend_error(error_type, "Method %s::%s() must take exactly 2 arguments", ZSTR_VAL(ce->name), ZEND_CALL_FUNC_NAME); - } else if (QUICK_ARG_SHOULD_BE_SENT_BY_REF(fptr, 1) || QUICK_ARG_SHOULD_BE_SENT_BY_REF(fptr, 2)) { - zend_error(error_type, "Method %s::%s() cannot take arguments by reference", ZSTR_VAL(ce->name), ZEND_CALL_FUNC_NAME); - } - } else if (name_len == sizeof(ZEND_CALLSTATIC_FUNC_NAME) - 1 && - !memcmp(lcname, ZEND_CALLSTATIC_FUNC_NAME, sizeof(ZEND_CALLSTATIC_FUNC_NAME)-1) - ) { - if (fptr->common.num_args != 2) { - zend_error(error_type, "Method %s::__callStatic() must take exactly 2 arguments", ZSTR_VAL(ce->name)); - } else if (QUICK_ARG_SHOULD_BE_SENT_BY_REF(fptr, 1) || QUICK_ARG_SHOULD_BE_SENT_BY_REF(fptr, 2)) { - zend_error(error_type, "Method %s::__callStatic() cannot take arguments by reference", ZSTR_VAL(ce->name)); - } - } else if (name_len == sizeof(ZEND_TOSTRING_FUNC_NAME) - 1 && - !memcmp(lcname, ZEND_TOSTRING_FUNC_NAME, sizeof(ZEND_TOSTRING_FUNC_NAME)-1) && fptr->common.num_args != 0 - ) { - zend_error(error_type, "Method %s::%s() cannot take arguments", ZSTR_VAL(ce->name), ZEND_TOSTRING_FUNC_NAME); - } else if (name_len == sizeof(ZEND_DEBUGINFO_FUNC_NAME) - 1 && - !memcmp(lcname, ZEND_DEBUGINFO_FUNC_NAME, sizeof(ZEND_DEBUGINFO_FUNC_NAME)-1) && fptr->common.num_args != 0) { - zend_error(error_type, "Method %s::%s() cannot take arguments", ZSTR_VAL(ce->name), ZEND_DEBUGINFO_FUNC_NAME); + if (zend_string_equals_literal(lcname, ZEND_CONSTRUCTOR_FUNC_NAME)) { + zend_check_magic_method_non_static(ce, fptr, error_type); + zend_check_magic_method_no_return_type(ce, fptr, error_type); + } else if (zend_string_equals_literal(lcname, ZEND_DESTRUCTOR_FUNC_NAME)) { + zend_check_magic_method_args(0, ce, fptr, error_type); + zend_check_magic_method_non_static(ce, fptr, error_type); + zend_check_magic_method_no_return_type(ce, fptr, error_type); + } else if (zend_string_equals_literal(lcname, ZEND_CLONE_FUNC_NAME)) { + zend_check_magic_method_args(0, ce, fptr, error_type); + zend_check_magic_method_non_static(ce, fptr, error_type); + zend_check_magic_method_return_type(ce, fptr, error_type, MAY_BE_VOID); + } else if (zend_string_equals_literal(lcname, ZEND_GET_FUNC_NAME)) { + zend_check_magic_method_args(1, ce, fptr, error_type); + zend_check_magic_method_non_static(ce, fptr, error_type); + zend_check_magic_method_public(ce, fptr, error_type); + zend_check_magic_method_arg_type(0, ce, fptr, error_type, MAY_BE_STRING); + } else if (zend_string_equals_literal(lcname, ZEND_SET_FUNC_NAME)) { + zend_check_magic_method_args(2, ce, fptr, error_type); + zend_check_magic_method_non_static(ce, fptr, error_type); + zend_check_magic_method_public(ce, fptr, error_type); + zend_check_magic_method_arg_type(0, ce, fptr, error_type, MAY_BE_STRING); + zend_check_magic_method_return_type(ce, fptr, error_type, MAY_BE_VOID); + } else if (zend_string_equals_literal(lcname, ZEND_UNSET_FUNC_NAME)) { + zend_check_magic_method_args(1, ce, fptr, error_type); + zend_check_magic_method_non_static(ce, fptr, error_type); + zend_check_magic_method_public(ce, fptr, error_type); + zend_check_magic_method_arg_type(0, ce, fptr, error_type, MAY_BE_STRING); + zend_check_magic_method_return_type(ce, fptr, error_type, MAY_BE_VOID); + } else if (zend_string_equals_literal(lcname, ZEND_ISSET_FUNC_NAME)) { + zend_check_magic_method_args(1, ce, fptr, error_type); + zend_check_magic_method_non_static(ce, fptr, error_type); + zend_check_magic_method_public(ce, fptr, error_type); + zend_check_magic_method_arg_type(0, ce, fptr, error_type, MAY_BE_STRING); + zend_check_magic_method_return_type(ce, fptr, error_type, MAY_BE_BOOL); + } else if (zend_string_equals_literal(lcname, ZEND_CALL_FUNC_NAME)) { + zend_check_magic_method_args(2, ce, fptr, error_type); + zend_check_magic_method_non_static(ce, fptr, error_type); + zend_check_magic_method_public(ce, fptr, error_type); + zend_check_magic_method_arg_type(0, ce, fptr, error_type, MAY_BE_STRING); + zend_check_magic_method_arg_type(1, ce, fptr, error_type, MAY_BE_ARRAY); + } else if (zend_string_equals_literal(lcname, ZEND_CALLSTATIC_FUNC_NAME)) { + zend_check_magic_method_args(2, ce, fptr, error_type); + zend_check_magic_method_static(ce, fptr, error_type); + zend_check_magic_method_public(ce, fptr, error_type); + zend_check_magic_method_arg_type(0, ce, fptr, error_type, MAY_BE_STRING); + zend_check_magic_method_arg_type(1, ce, fptr, error_type, MAY_BE_ARRAY); + } else if (zend_string_equals_literal(lcname, ZEND_TOSTRING_FUNC_NAME)) { + zend_check_magic_method_args(0, ce, fptr, error_type); + zend_check_magic_method_non_static(ce, fptr, error_type); + zend_check_magic_method_public(ce, fptr, error_type); + } else if (zend_string_equals_literal(lcname, ZEND_DEBUGINFO_FUNC_NAME)) { + zend_check_magic_method_args(0, ce, fptr, error_type); + zend_check_magic_method_non_static(ce, fptr, error_type); + zend_check_magic_method_public(ce, fptr, error_type); + zend_check_magic_method_return_type(ce, fptr, error_type, (MAY_BE_ARRAY | MAY_BE_NULL)); + } else if (zend_string_equals_literal(lcname, "__serialize")) { + zend_check_magic_method_args(0, ce, fptr, error_type); + zend_check_magic_method_non_static(ce, fptr, error_type); + zend_check_magic_method_public(ce, fptr, error_type); + zend_check_magic_method_return_type(ce, fptr, error_type, MAY_BE_ARRAY); + } else if (zend_string_equals_literal(lcname, "__unserialize")) { + zend_check_magic_method_args(1, ce, fptr, error_type); + zend_check_magic_method_non_static(ce, fptr, error_type); + zend_check_magic_method_public(ce, fptr, error_type); + zend_check_magic_method_arg_type(0, ce, fptr, error_type, MAY_BE_ARRAY); + zend_check_magic_method_return_type(ce, fptr, error_type, MAY_BE_VOID); + } else if (zend_string_equals_literal(lcname, "__set_state")) { + zend_check_magic_method_args(1, ce, fptr, error_type); + zend_check_magic_method_static(ce, fptr, error_type); + zend_check_magic_method_public(ce, fptr, error_type); + zend_check_magic_method_arg_type(0, ce, fptr, error_type, MAY_BE_ARRAY); + zend_check_magic_method_return_type(ce, fptr, error_type, MAY_BE_OBJECT); + } else if (zend_string_equals_literal(lcname, "__invoke")) { + zend_check_magic_method_non_static(ce, fptr, error_type); + zend_check_magic_method_public(ce, fptr, error_type); + } else if (zend_string_equals_literal(lcname, "__sleep")) { + zend_check_magic_method_args(0, ce, fptr, error_type); + zend_check_magic_method_non_static(ce, fptr, error_type); + zend_check_magic_method_public(ce, fptr, error_type); + zend_check_magic_method_return_type(ce, fptr, error_type, MAY_BE_ARRAY); + } else if (zend_string_equals_literal(lcname, "__wakeup")) { + zend_check_magic_method_args(0, ce, fptr, error_type); + zend_check_magic_method_non_static(ce, fptr, error_type); + zend_check_magic_method_public(ce, fptr, error_type); + zend_check_magic_method_return_type(ce, fptr, error_type, MAY_BE_VOID); + } +} +/* }}} */ + +ZEND_API void zend_add_magic_method(zend_class_entry *ce, zend_function *fptr, zend_string *lcname) +{ + if (ZSTR_VAL(lcname)[0] != '_' || ZSTR_VAL(lcname)[1] != '_') { + /* pass */ + } else if (zend_string_equals_literal(lcname, ZEND_CLONE_FUNC_NAME)) { + ce->clone = fptr; + } else if (zend_string_equals_literal(lcname, ZEND_CONSTRUCTOR_FUNC_NAME)) { + ce->constructor = fptr; + ce->constructor->common.fn_flags |= ZEND_ACC_CTOR; + } else if (zend_string_equals_literal(lcname, ZEND_DESTRUCTOR_FUNC_NAME)) { + ce->destructor = fptr; + } else if (zend_string_equals_literal(lcname, ZEND_GET_FUNC_NAME)) { + ce->__get = fptr; + ce->ce_flags |= ZEND_ACC_USE_GUARDS; + } else if (zend_string_equals_literal(lcname, ZEND_SET_FUNC_NAME)) { + ce->__set = fptr; + ce->ce_flags |= ZEND_ACC_USE_GUARDS; + } else if (zend_string_equals_literal(lcname, ZEND_CALL_FUNC_NAME)) { + ce->__call = fptr; + } else if (zend_string_equals_literal(lcname, ZEND_UNSET_FUNC_NAME)) { + ce->__unset = fptr; + ce->ce_flags |= ZEND_ACC_USE_GUARDS; + } else if (zend_string_equals_literal(lcname, ZEND_ISSET_FUNC_NAME)) { + ce->__isset = fptr; + ce->ce_flags |= ZEND_ACC_USE_GUARDS; + } else if (zend_string_equals_literal(lcname, ZEND_CALLSTATIC_FUNC_NAME)) { + ce->__callstatic = fptr; + } else if (zend_string_equals_literal(lcname, ZEND_TOSTRING_FUNC_NAME)) { + ce->__tostring = fptr; + } else if (zend_string_equals_literal(lcname, ZEND_DEBUGINFO_FUNC_NAME)) { + ce->__debugInfo = fptr; + } else if (zend_string_equals_literal(lcname, "__serialize")) { + ce->__serialize = fptr; + } else if (zend_string_equals_literal(lcname, "__unserialize")) { + ce->__unserialize = fptr; } } -/* }}} */ /* registers all functions in *library_functions in the function hash */ -ZEND_API int zend_register_functions(zend_class_entry *scope, const zend_function_entry *functions, HashTable *function_table, int type) /* {{{ */ +ZEND_API zend_result zend_register_functions(zend_class_entry *scope, const zend_function_entry *functions, HashTable *function_table, int type) /* {{{ */ { const zend_function_entry *ptr = functions; zend_function function, *reg_function; @@ -2145,11 +2266,8 @@ ZEND_API int zend_register_functions(zend_class_entry *scope, const zend_functio int count=0, unload=0; HashTable *target_function_table = function_table; int error_type; - zend_function *ctor = NULL, *dtor = NULL, *clone = NULL, *__get = NULL, *__set = NULL, *__unset = NULL, *__isset = NULL, *__call = NULL, *__callstatic = NULL, *__tostring = NULL, *__debugInfo = NULL, *serialize_func = NULL, *unserialize_func = NULL; zend_string *lowercase_name; size_t fname_len; - const char *lc_class_name = NULL; - size_t class_name_len = 0; if (type==MODULE_PERSISTENT) { error_type = E_CORE_WARNING; @@ -2164,17 +2282,6 @@ ZEND_API int zend_register_functions(zend_class_entry *scope, const zend_functio internal_function->module = EG(current_module); memset(internal_function->reserved, 0, ZEND_MAX_RESERVED_RESOURCES * sizeof(void*)); - if (scope) { - class_name_len = ZSTR_LEN(scope->name); - if ((lc_class_name = zend_memrchr(ZSTR_VAL(scope->name), '\\', class_name_len))) { - ++lc_class_name; - class_name_len -= (lc_class_name - ZSTR_VAL(scope->name)); - lc_class_name = zend_str_tolower_dup(lc_class_name, class_name_len); - } else { - lc_class_name = zend_str_tolower_dup(ZSTR_VAL(scope->name), class_name_len); - } - } - while (ptr->fname) { fname_len = strlen(ptr->fname); internal_function->handler = ptr->handler; @@ -2193,9 +2300,9 @@ ZEND_API int zend_register_functions(zend_class_entry *scope, const zend_functio } else { internal_function->fn_flags = ZEND_ACC_PUBLIC; } + if (ptr->arg_info) { zend_internal_function_info *info = (zend_internal_function_info*)ptr->arg_info; - internal_function->arg_info = (zend_internal_arg_info*)ptr->arg_info+1; internal_function->num_args = ptr->num_args; /* Currently you cannot denote that the function can accept less arguments than num_args */ @@ -2204,21 +2311,17 @@ ZEND_API int zend_register_functions(zend_class_entry *scope, const zend_functio } else { internal_function->required_num_args = info->required_num_args; } - if (info->return_reference) { + if (ZEND_ARG_SEND_MODE(info)) { internal_function->fn_flags |= ZEND_ACC_RETURN_REFERENCE; } - if (ptr->arg_info[ptr->num_args].is_variadic) { + if (ZEND_ARG_IS_VARIADIC(&ptr->arg_info[ptr->num_args])) { internal_function->fn_flags |= ZEND_ACC_VARIADIC; /* Don't count the variadic argument */ internal_function->num_args--; } if (ZEND_TYPE_IS_SET(info->type)) { - if (ZEND_TYPE_IS_CLASS(info->type)) { - const char *type_name = (const char*)info->type; - - if (type_name[0] == '?') { - type_name++; - } + if (ZEND_TYPE_HAS_NAME(info->type)) { + const char *type_name = ZEND_TYPE_LITERAL_NAME(info->type); if (!scope && (!strcasecmp(type_name, "self") || !strcasecmp(type_name, "parent"))) { zend_error_noreturn(E_CORE_ERROR, "Cannot declare a return type of %s outside of a class scope", type_name); } @@ -2227,10 +2330,14 @@ ZEND_API int zend_register_functions(zend_class_entry *scope, const zend_functio internal_function->fn_flags |= ZEND_ACC_HAS_RETURN_TYPE; } } else { + zend_error(E_CORE_WARNING, "Missing arginfo for %s%s%s()", + scope ? ZSTR_VAL(scope->name) : "", scope ? "::" : "", ptr->fname); + internal_function->arg_info = NULL; internal_function->num_args = 0; internal_function->required_num_args = 0; } + zend_set_function_arg_flags((zend_function*)internal_function); if (ptr->flags & ZEND_ACC_ABSTRACT) { if (scope) { @@ -2243,19 +2350,15 @@ ZEND_API int zend_register_functions(zend_class_entry *scope, const zend_functio scope->ce_flags |= ZEND_ACC_EXPLICIT_ABSTRACT_CLASS; } } - if (ptr->flags & ZEND_ACC_STATIC && (!scope || !(scope->ce_flags & ZEND_ACC_INTERFACE))) { + if ((ptr->flags & ZEND_ACC_STATIC) && (!scope || !(scope->ce_flags & ZEND_ACC_INTERFACE))) { zend_error(error_type, "Static function %s%s%s() cannot be abstract", scope ? ZSTR_VAL(scope->name) : "", scope ? "::" : "", ptr->fname); } } else { if (scope && (scope->ce_flags & ZEND_ACC_INTERFACE)) { - efree((char*)lc_class_name); zend_error(error_type, "Interface %s cannot contain non abstract method %s()", ZSTR_VAL(scope->name), ptr->fname); return FAILURE; } if (!internal_function->handler) { - if (scope) { - efree((char*)lc_class_name); - } zend_error(error_type, "Method %s%s%s() cannot be a NULL function", scope ? ZSTR_VAL(scope->name) : "", scope ? "::" : "", ptr->fname); zend_unregister_functions(functions, count, target_function_table); return FAILURE; @@ -2272,14 +2375,30 @@ ZEND_API int zend_register_functions(zend_class_entry *scope, const zend_functio break; } + /* Get parameter count including variadic parameter. */ + uint32_t num_args = reg_function->common.num_args; + if (reg_function->common.fn_flags & ZEND_ACC_VARIADIC) { + num_args++; + } + /* If types of arguments have to be checked */ - if (reg_function->common.arg_info && reg_function->common.num_args) { + if (reg_function->common.arg_info && num_args) { uint32_t i; - for (i = 0; i < reg_function->common.num_args; i++) { - if (ZEND_TYPE_IS_SET(reg_function->common.arg_info[i].type)) { + for (i = 0; i < num_args; i++) { + zend_internal_arg_info *arg_info = ®_function->internal_function.arg_info[i]; + ZEND_ASSERT(arg_info->name && "Parameter must have a name"); + if (ZEND_TYPE_IS_SET(arg_info->type)) { reg_function->common.fn_flags |= ZEND_ACC_HAS_TYPE_HINTS; - break; } +#if ZEND_DEBUG + for (uint32_t j = 0; j < i; j++) { + if (!strcmp(arg_info->name, reg_function->internal_function.arg_info[j].name)) { + zend_error_noreturn(E_CORE_ERROR, + "Duplicate parameter name $%s for function %s%s%s()", arg_info->name, + scope ? ZSTR_VAL(scope->name) : "", scope ? "::" : "", ptr->fname); + } + } +#endif } } @@ -2287,89 +2406,35 @@ ZEND_API int zend_register_functions(zend_class_entry *scope, const zend_functio (reg_function->common.fn_flags & (ZEND_ACC_HAS_RETURN_TYPE|ZEND_ACC_HAS_TYPE_HINTS))) { /* convert "const char*" class type names into "zend_string*" */ uint32_t i; - uint32_t num_args = reg_function->common.num_args + 1; zend_arg_info *arg_info = reg_function->common.arg_info - 1; zend_arg_info *new_arg_info; - if (reg_function->common.fn_flags & ZEND_ACC_VARIADIC) { - num_args++; - } + /* Treat return type as an extra argument */ + num_args++; new_arg_info = malloc(sizeof(zend_arg_info) * num_args); memcpy(new_arg_info, arg_info, sizeof(zend_arg_info) * num_args); reg_function->common.arg_info = new_arg_info + 1; for (i = 0; i < num_args; i++) { - if (ZEND_TYPE_IS_CLASS(new_arg_info[i].type)) { - const char *class_name = (const char*)new_arg_info[i].type; - zend_bool allow_null = 0; - zend_string *str; - - if (class_name[0] == '?') { - class_name++; - allow_null = 1; - } - str = zend_string_init_interned(class_name, strlen(class_name), 1); - new_arg_info[i].type = ZEND_TYPE_ENCODE_CLASS(str, allow_null); + if (ZEND_TYPE_HAS_CLASS(new_arg_info[i].type)) { + ZEND_ASSERT(ZEND_TYPE_HAS_NAME(new_arg_info[i].type) + && "Only simple classes are currently supported"); + const char *class_name = ZEND_TYPE_LITERAL_NAME(new_arg_info[i].type); + ZEND_TYPE_SET_PTR(new_arg_info[i].type, + zend_string_init_interned(class_name, strlen(class_name), 1)); } } } if (scope) { - /* Look for ctor, dtor, clone - * If it's an old-style constructor, store it only if we don't have - * a constructor already. - */ - if ((fname_len == class_name_len) && !ctor && !memcmp(ZSTR_VAL(lowercase_name), lc_class_name, class_name_len+1)) { - ctor = reg_function; - } else if (zend_string_equals_literal(lowercase_name, "serialize")) { - serialize_func = reg_function; - } else if (zend_string_equals_literal(lowercase_name, "unserialize")) { - unserialize_func = reg_function; - } else if (ZSTR_VAL(lowercase_name)[0] != '_' || ZSTR_VAL(lowercase_name)[1] != '_') { - reg_function = NULL; - } else if (zend_string_equals_literal(lowercase_name, ZEND_CONSTRUCTOR_FUNC_NAME)) { - ctor = reg_function; - } else if (zend_string_equals_literal(lowercase_name, ZEND_DESTRUCTOR_FUNC_NAME)) { - dtor = reg_function; - if (internal_function->num_args) { - zend_error(error_type, "Destructor %s::%s() cannot take arguments", ZSTR_VAL(scope->name), ptr->fname); - } - } else if (zend_string_equals_literal(lowercase_name, ZEND_CLONE_FUNC_NAME)) { - clone = reg_function; - } else if (zend_string_equals_literal(lowercase_name, ZEND_CALL_FUNC_NAME)) { - __call = reg_function; - } else if (zend_string_equals_literal(lowercase_name, ZEND_CALLSTATIC_FUNC_NAME)) { - __callstatic = reg_function; - } else if (zend_string_equals_literal(lowercase_name, ZEND_TOSTRING_FUNC_NAME)) { - __tostring = reg_function; - } else if (zend_string_equals_literal(lowercase_name, ZEND_GET_FUNC_NAME)) { - __get = reg_function; - scope->ce_flags |= ZEND_ACC_USE_GUARDS; - } else if (zend_string_equals_literal(lowercase_name, ZEND_SET_FUNC_NAME)) { - __set = reg_function; - scope->ce_flags |= ZEND_ACC_USE_GUARDS; - } else if (zend_string_equals_literal(lowercase_name, ZEND_UNSET_FUNC_NAME)) { - __unset = reg_function; - scope->ce_flags |= ZEND_ACC_USE_GUARDS; - } else if (zend_string_equals_literal(lowercase_name, ZEND_ISSET_FUNC_NAME)) { - __isset = reg_function; - scope->ce_flags |= ZEND_ACC_USE_GUARDS; - } else if (zend_string_equals_literal(lowercase_name, ZEND_DEBUGINFO_FUNC_NAME)) { - __debugInfo = reg_function; - } else { - reg_function = NULL; - } - if (reg_function) { - zend_check_magic_method_implementation(scope, reg_function, error_type); - } + zend_check_magic_method_implementation( + scope, reg_function, lowercase_name, E_CORE_ERROR); + zend_add_magic_method(scope, reg_function, lowercase_name); } ptr++; count++; zend_string_release(lowercase_name); } if (unload) { /* before unloading, display all remaining bad function in the module */ - if (scope) { - efree((char*)lc_class_name); - } while (ptr->fname) { fname_len = strlen(ptr->fname); lowercase_name = zend_string_alloc(fname_len, 0); @@ -2383,101 +2448,6 @@ ZEND_API int zend_register_functions(zend_class_entry *scope, const zend_functio zend_unregister_functions(functions, count, target_function_table); return FAILURE; } - if (scope) { - scope->constructor = ctor; - scope->destructor = dtor; - scope->clone = clone; - scope->__call = __call; - scope->__callstatic = __callstatic; - scope->__tostring = __tostring; - scope->__get = __get; - scope->__set = __set; - scope->__unset = __unset; - scope->__isset = __isset; - scope->__debugInfo = __debugInfo; - scope->serialize_func = serialize_func; - scope->unserialize_func = unserialize_func; - if (ctor) { - ctor->common.fn_flags |= ZEND_ACC_CTOR; - if (ctor->common.fn_flags & ZEND_ACC_STATIC) { - zend_error(error_type, "Constructor %s::%s() cannot be static", ZSTR_VAL(scope->name), ZSTR_VAL(ctor->common.function_name)); - } - ctor->common.fn_flags &= ~ZEND_ACC_ALLOW_STATIC; - } - if (dtor) { - dtor->common.fn_flags |= ZEND_ACC_DTOR; - if (dtor->common.fn_flags & ZEND_ACC_STATIC) { - zend_error(error_type, "Destructor %s::%s() cannot be static", ZSTR_VAL(scope->name), ZSTR_VAL(dtor->common.function_name)); - } - dtor->common.fn_flags &= ~ZEND_ACC_ALLOW_STATIC; - } - if (clone) { - if (clone->common.fn_flags & ZEND_ACC_STATIC) { - zend_error(error_type, "%s::%s() cannot be static", ZSTR_VAL(scope->name), ZSTR_VAL(clone->common.function_name)); - } - clone->common.fn_flags &= ~ZEND_ACC_ALLOW_STATIC; - } - if (__call) { - if (__call->common.fn_flags & ZEND_ACC_STATIC) { - zend_error(error_type, "Method %s::%s() cannot be static", ZSTR_VAL(scope->name), ZSTR_VAL(__call->common.function_name)); - } - __call->common.fn_flags &= ~ZEND_ACC_ALLOW_STATIC; - } - if (__callstatic) { - if (!(__callstatic->common.fn_flags & ZEND_ACC_STATIC)) { - zend_error(error_type, "Method %s::%s() must be static", ZSTR_VAL(scope->name), ZSTR_VAL(__callstatic->common.function_name)); - } - __callstatic->common.fn_flags |= ZEND_ACC_STATIC; - } - if (__tostring) { - if (__tostring->common.fn_flags & ZEND_ACC_STATIC) { - zend_error(error_type, "Method %s::%s() cannot be static", ZSTR_VAL(scope->name), ZSTR_VAL(__tostring->common.function_name)); - } - __tostring->common.fn_flags &= ~ZEND_ACC_ALLOW_STATIC; - } - if (__get) { - if (__get->common.fn_flags & ZEND_ACC_STATIC) { - zend_error(error_type, "Method %s::%s() cannot be static", ZSTR_VAL(scope->name), ZSTR_VAL(__get->common.function_name)); - } - __get->common.fn_flags &= ~ZEND_ACC_ALLOW_STATIC; - } - if (__set) { - if (__set->common.fn_flags & ZEND_ACC_STATIC) { - zend_error(error_type, "Method %s::%s() cannot be static", ZSTR_VAL(scope->name), ZSTR_VAL(__set->common.function_name)); - } - __set->common.fn_flags &= ~ZEND_ACC_ALLOW_STATIC; - } - if (__unset) { - if (__unset->common.fn_flags & ZEND_ACC_STATIC) { - zend_error(error_type, "Method %s::%s() cannot be static", ZSTR_VAL(scope->name), ZSTR_VAL(__unset->common.function_name)); - } - __unset->common.fn_flags &= ~ZEND_ACC_ALLOW_STATIC; - } - if (__isset) { - if (__isset->common.fn_flags & ZEND_ACC_STATIC) { - zend_error(error_type, "Method %s::%s() cannot be static", ZSTR_VAL(scope->name), ZSTR_VAL(__isset->common.function_name)); - } - __isset->common.fn_flags &= ~ZEND_ACC_ALLOW_STATIC; - } - if (__debugInfo) { - if (__debugInfo->common.fn_flags & ZEND_ACC_STATIC) { - zend_error(error_type, "Method %s::%s() cannot be static", ZSTR_VAL(scope->name), ZSTR_VAL(__debugInfo->common.function_name)); - } - } - - if (ctor && (ctor->common.fn_flags & ZEND_ACC_HAS_RETURN_TYPE)) { - zend_error_noreturn(E_CORE_ERROR, "Constructor %s::%s() cannot declare a return type", ZSTR_VAL(scope->name), ZSTR_VAL(ctor->common.function_name)); - } - - if (dtor && (dtor->common.fn_flags & ZEND_ACC_HAS_RETURN_TYPE)) { - zend_error_noreturn(E_CORE_ERROR, "Destructor %s::%s() cannot declare a return type", ZSTR_VAL(scope->name), ZSTR_VAL(dtor->common.function_name)); - } - - if (clone && (clone->common.fn_flags & ZEND_ACC_HAS_RETURN_TYPE)) { - zend_error_noreturn(E_CORE_ERROR, "%s::%s() cannot declare a return type", ZSTR_VAL(scope->name), ZSTR_VAL(clone->common.function_name)); - } - efree((char*)lc_class_name); - } return SUCCESS; } /* }}} */ @@ -2511,7 +2481,7 @@ ZEND_API void zend_unregister_functions(const zend_function_entry *functions, in } /* }}} */ -ZEND_API int zend_startup_module(zend_module_entry *module) /* {{{ */ +ZEND_API zend_result zend_startup_module(zend_module_entry *module) /* {{{ */ { if ((module = zend_register_internal_module(module)) != NULL && zend_startup_module_ex(module) == SUCCESS) { return SUCCESS; @@ -2520,7 +2490,7 @@ ZEND_API int zend_startup_module(zend_module_entry *module) /* {{{ */ } /* }}} */ -ZEND_API int zend_get_module_started(const char *module_name) /* {{{ */ +ZEND_API zend_result zend_get_module_started(const char *module_name) /* {{{ */ { zend_module_entry *module; @@ -2701,7 +2671,7 @@ static zend_class_entry *do_register_internal_class(zend_class_entry *orig_class class_entry->type = ZEND_INTERNAL_CLASS; zend_initialize_class_data(class_entry, 0); - class_entry->ce_flags = ce_flags | ZEND_ACC_CONSTANTS_UPDATED | ZEND_ACC_LINKED | ZEND_ACC_RESOLVED_PARENT | ZEND_ACC_RESOLVED_INTERFACES; + class_entry->ce_flags = orig_class_entry->ce_flags | ce_flags | ZEND_ACC_CONSTANTS_UPDATED | ZEND_ACC_LINKED | ZEND_ACC_RESOLVED_PARENT | ZEND_ACC_RESOLVED_INTERFACES; class_entry->info.internal.module = EG(current_module); if (class_entry->info.internal.builtin_functions) { @@ -2764,7 +2734,7 @@ ZEND_API zend_class_entry *zend_register_internal_interface(zend_class_entry *or } /* }}} */ -ZEND_API int zend_register_class_alias_ex(const char *name, size_t name_len, zend_class_entry *ce, int persistent) /* {{{ */ +ZEND_API zend_result zend_register_class_alias_ex(const char *name, size_t name_len, zend_class_entry *ce, bool persistent) /* {{{ */ { zend_string *lcname; zval zv, *ret; @@ -2799,7 +2769,8 @@ ZEND_API int zend_register_class_alias_ex(const char *name, size_t name_len, zen } /* }}} */ -ZEND_API int zend_set_hash_symbol(zval *symbol, const char *name, int name_length, zend_bool is_ref, int num_symbol_tables, ...) /* {{{ */ +// TODO num_symbol_tables as unsigned int? +ZEND_API zend_result zend_set_hash_symbol(zval *symbol, const char *name, size_t name_length, zend_bool is_ref, int num_symbol_tables, ...) /* {{{ */ { HashTable *symbol_table; va_list symbol_table_list; @@ -2823,26 +2794,43 @@ ZEND_API int zend_set_hash_symbol(zval *symbol, const char *name, int name_lengt /* Disabled functions support */ -/* {{{ proto void display_disabled_function(void) -Dummy function which displays an error when a disabled function is called. */ -ZEND_API ZEND_COLD ZEND_FUNCTION(display_disabled_function) +static void zend_disable_function(const char *function_name, size_t function_name_length) { - zend_error(E_WARNING, "%s() has been disabled for security reasons", get_active_function_name()); + zend_hash_str_del(CG(function_table), function_name, function_name_length); } -/* }}} */ -ZEND_API int zend_disable_function(char *function_name, size_t function_name_length) /* {{{ */ +ZEND_API void zend_disable_functions(const char *function_list) /* {{{ */ { - zend_internal_function *func; - if ((func = zend_hash_str_find_ptr(CG(function_table), function_name, function_name_length))) { - zend_free_internal_arg_info(func); - func->fn_flags &= ~(ZEND_ACC_VARIADIC | ZEND_ACC_HAS_TYPE_HINTS | ZEND_ACC_HAS_RETURN_TYPE); - func->num_args = 0; - func->arg_info = NULL; - func->handler = ZEND_FN(display_disabled_function); - return SUCCESS; + if (!function_list || !*function_list) { + return; } - return FAILURE; + + const char *s = NULL, *e = function_list; + while (*e) { + switch (*e) { + case ' ': + case ',': + if (s) { + zend_disable_function(s, e - s); + s = NULL; + } + break; + default: + if (!s) { + s = e; + } + break; + } + e++; + } + if (s) { + zend_disable_function(s, e - s); + } + + /* Rehash the function table after deleting functions. This ensures that all internal + * functions are contiguous, which means we don't need to perform full table cleanup + * on shutdown. */ + zend_hash_rehash(CG(function_table)); } /* }}} */ @@ -2877,7 +2865,7 @@ static const zend_function_entry disabled_class_new[] = { ZEND_FE_END }; -ZEND_API int zend_disable_class(char *class_name, size_t class_name_length) /* {{{ */ +ZEND_API zend_result zend_disable_class(const char *class_name, size_t class_name_length) /* {{{ */ { zend_class_entry *disabled_class; zend_string *key; @@ -2905,9 +2893,14 @@ ZEND_API int zend_disable_class(char *class_name, size_t class_name_length) /* { } /* }}} */ -static int zend_is_callable_check_class(zend_string *name, zend_class_entry *scope, zend_fcall_info_cache *fcc, int *strict_class, char **error) /* {{{ */ +static zend_always_inline zend_class_entry *get_scope(zend_execute_data *frame) +{ + return frame && frame->func ? frame->func->common.scope : NULL; +} + +static bool zend_is_callable_check_class(zend_string *name, zend_class_entry *scope, zend_execute_data *frame, zend_fcall_info_cache *fcc, bool *strict_class, char **error) /* {{{ */ { - int ret = 0; + bool ret = 0; zend_class_entry *ce; size_t name_len = ZSTR_LEN(name); zend_string *lcname; @@ -2919,54 +2912,48 @@ static int zend_is_callable_check_class(zend_string *name, zend_class_entry *sco *strict_class = 0; if (zend_string_equals_literal(lcname, "self")) { if (!scope) { - if (error) *error = estrdup("cannot access self:: when no class scope is active"); + if (error) *error = estrdup("cannot access \"self\" when no class scope is active"); } else { - fcc->called_scope = zend_get_called_scope(EG(current_execute_data)); + fcc->called_scope = zend_get_called_scope(frame); fcc->calling_scope = scope; if (!fcc->object) { - fcc->object = zend_get_this_object(EG(current_execute_data)); + fcc->object = zend_get_this_object(frame); } ret = 1; } } else if (zend_string_equals_literal(lcname, "parent")) { if (!scope) { - if (error) *error = estrdup("cannot access parent:: when no class scope is active"); + if (error) *error = estrdup("cannot access \"parent\" when no class scope is active"); } else if (!scope->parent) { - if (error) *error = estrdup("cannot access parent:: when current class scope has no parent"); + if (error) *error = estrdup("cannot access \"parent\" when current class scope has no parent"); } else { - fcc->called_scope = zend_get_called_scope(EG(current_execute_data)); + fcc->called_scope = zend_get_called_scope(frame); fcc->calling_scope = scope->parent; if (!fcc->object) { - fcc->object = zend_get_this_object(EG(current_execute_data)); + fcc->object = zend_get_this_object(frame); } *strict_class = 1; ret = 1; } } else if (zend_string_equals_literal(lcname, "static")) { - zend_class_entry *called_scope = zend_get_called_scope(EG(current_execute_data)); + zend_class_entry *called_scope = zend_get_called_scope(frame); if (!called_scope) { - if (error) *error = estrdup("cannot access static:: when no class scope is active"); + if (error) *error = estrdup("cannot access \"static\" when no class scope is active"); } else { fcc->called_scope = called_scope; fcc->calling_scope = called_scope; if (!fcc->object) { - fcc->object = zend_get_this_object(EG(current_execute_data)); + fcc->object = zend_get_this_object(frame); } *strict_class = 1; ret = 1; } } else if ((ce = zend_lookup_class(name)) != NULL) { - zend_class_entry *scope; - zend_execute_data *ex = EG(current_execute_data); - - while (ex && (!ex->func || !ZEND_USER_CODE(ex->func->type))) { - ex = ex->prev_execute_data; - } - scope = ex ? ex->func->common.scope : NULL; + zend_class_entry *scope = get_scope(frame); fcc->calling_scope = ce; if (scope && !fcc->object) { - zend_object *object = zend_get_this_object(EG(current_execute_data)); + zend_object *object = zend_get_this_object(frame); if (object && instanceof_function(object->ce, scope) && @@ -2982,7 +2969,7 @@ static int zend_is_callable_check_class(zend_string *name, zend_class_entry *sco *strict_class = 1; ret = 1; } else { - if (error) zend_spprintf(error, 0, "class '%.*s' not found", (int)name_len, ZSTR_VAL(name)); + if (error) zend_spprintf(error, 0, "class \"%.*s\" not found", (int)name_len, ZSTR_VAL(name)); } ZSTR_ALLOCA_FREE(lcname, use_heap); return ret; @@ -2991,22 +2978,19 @@ static int zend_is_callable_check_class(zend_string *name, zend_class_entry *sco ZEND_API void zend_release_fcall_info_cache(zend_fcall_info_cache *fcc) { if (fcc->function_handler && - ((fcc->function_handler->common.fn_flags & ZEND_ACC_CALL_VIA_TRAMPOLINE) || - fcc->function_handler->type == ZEND_OVERLOADED_FUNCTION_TEMPORARY || - fcc->function_handler->type == ZEND_OVERLOADED_FUNCTION)) { - if (fcc->function_handler->type != ZEND_OVERLOADED_FUNCTION && - fcc->function_handler->common.function_name) { + (fcc->function_handler->common.fn_flags & ZEND_ACC_CALL_VIA_TRAMPOLINE)) { + if (fcc->function_handler->common.function_name) { zend_string_release_ex(fcc->function_handler->common.function_name, 0); } zend_free_trampoline(fcc->function_handler); + fcc->function_handler = NULL; } - fcc->function_handler = NULL; } -static zend_always_inline int zend_is_callable_check_func(int check_flags, zval *callable, zend_fcall_info_cache *fcc, int strict_class, char **error) /* {{{ */ +static zend_always_inline bool zend_is_callable_check_func(int check_flags, zval *callable, zend_execute_data *frame, zend_fcall_info_cache *fcc, bool strict_class, char **error) /* {{{ */ { zend_class_entry *ce_org = fcc->calling_scope; - int retval = 0; + bool retval = 0; zend_string *mname, *cname; zend_string *lmname; const char *colon; @@ -3068,11 +3052,11 @@ static zend_always_inline int zend_is_callable_check_func(int check_flags, zval if (ce_org) { scope = ce_org; } else { - scope = zend_get_executed_scope(); + scope = get_scope(frame); } cname = zend_string_init(Z_STRVAL_P(callable), clen, 0); - if (!zend_is_callable_check_class(cname, scope, fcc, &strict_class, error)) { + if (!zend_is_callable_check_class(cname, scope, frame, fcc, &strict_class, error)) { zend_string_release_ex(cname, 0); return 0; } @@ -3080,7 +3064,7 @@ static zend_always_inline int zend_is_callable_check_func(int check_flags, zval ftable = &fcc->calling_scope->function_table; if (ce_org && !instanceof_function(ce_org, fcc->calling_scope)) { - if (error) zend_spprintf(error, 0, "class '%s' is not a subclass of '%s'", ZSTR_VAL(ce_org->name), ZSTR_VAL(fcc->calling_scope->name)); + if (error) zend_spprintf(error, 0, "class %s is not a subclass of %s", ZSTR_VAL(ce_org->name), ZSTR_VAL(fcc->calling_scope->name)); return 0; } mname = zend_string_init(Z_STRVAL_P(callable) + clen + 2, mlen, 0); @@ -3093,7 +3077,7 @@ static zend_always_inline int zend_is_callable_check_func(int check_flags, zval } else { /* We already checked for plain function before. */ if (error && !(check_flags & IS_CALLABLE_CHECK_SILENT)) { - zend_spprintf(error, 0, "function '%s' not found or invalid function name", Z_STRVAL_P(callable)); + zend_spprintf(error, 0, "function \"%s\" not found or invalid function name", Z_STRVAL_P(callable)); } return 0; } @@ -3111,7 +3095,7 @@ static zend_always_inline int zend_is_callable_check_func(int check_flags, zval retval = 1; if ((fcc->function_handler->op_array.fn_flags & ZEND_ACC_CHANGED) && !strict_class) { - scope = zend_get_executed_scope(); + scope = get_scope(frame); if (scope && instanceof_function(fcc->function_handler->common.scope, scope)) { @@ -3119,7 +3103,7 @@ static zend_always_inline int zend_is_callable_check_func(int check_flags, zval if (zv != NULL) { zend_function *priv_fbc = Z_PTR_P(zv); - if (priv_fbc->common.fn_flags & ZEND_ACC_PRIVATE + if ((priv_fbc->common.fn_flags & ZEND_ACC_PRIVATE) && priv_fbc->common.scope == scope) { fcc->function_handler = priv_fbc; } @@ -3127,11 +3111,10 @@ static zend_always_inline int zend_is_callable_check_func(int check_flags, zval } } if (!(fcc->function_handler->common.fn_flags & ZEND_ACC_PUBLIC) && - !(check_flags & IS_CALLABLE_CHECK_NO_ACCESS) && (fcc->calling_scope && ((fcc->object && fcc->calling_scope->__call) || (!fcc->object && fcc->calling_scope->__callstatic)))) { - scope = zend_get_executed_scope(); + scope = get_scope(frame); if (fcc->function_handler->common.scope != scope) { if ((fcc->function_handler->common.fn_flags & ZEND_ACC_PRIVATE) || !zend_check_protected(zend_get_function_root_class(fcc->function_handler), scope)) { @@ -3171,7 +3154,7 @@ get_function_via_handler: retval = 1; call_via_handler = (fcc->function_handler->common.fn_flags & ZEND_ACC_CALL_VIA_TRAMPOLINE) != 0; if (call_via_handler && !fcc->object) { - zend_object *object = zend_get_this_object(EG(current_execute_data)); + zend_object *object = zend_get_this_object(frame); if (object && instanceof_function(object->ce, fcc->calling_scope)) { fcc->object = object; @@ -3189,36 +3172,14 @@ get_function_via_handler: zend_spprintf(error, 0, "cannot call abstract method %s::%s()", ZSTR_VAL(fcc->calling_scope->name), ZSTR_VAL(fcc->function_handler->common.function_name)); } } else if (!fcc->object && !(fcc->function_handler->common.fn_flags & ZEND_ACC_STATIC)) { - int severity; - char *verb; - if (fcc->function_handler->common.fn_flags & ZEND_ACC_ALLOW_STATIC) { - severity = E_DEPRECATED; - verb = "should not"; - } else { - /* An internal function assumes $this is present and won't check that. So PHP would crash by allowing the call. */ - severity = E_ERROR; - verb = "cannot"; - } - if ((check_flags & IS_CALLABLE_CHECK_IS_STATIC) != 0) { - retval = 0; - } + retval = 0; if (error) { - zend_spprintf(error, 0, "non-static method %s::%s() %s be called statically", ZSTR_VAL(fcc->calling_scope->name), ZSTR_VAL(fcc->function_handler->common.function_name), verb); - if (severity != E_DEPRECATED) { - retval = 0; - } - } else if (retval) { - if (severity == E_ERROR) { - zend_throw_error(NULL, "Non-static method %s::%s() %s be called statically", ZSTR_VAL(fcc->calling_scope->name), ZSTR_VAL(fcc->function_handler->common.function_name), verb); - } else { - zend_error(severity, "Non-static method %s::%s() %s be called statically", ZSTR_VAL(fcc->calling_scope->name), ZSTR_VAL(fcc->function_handler->common.function_name), verb); - } + zend_spprintf(error, 0, "non-static method %s::%s() cannot be called statically", ZSTR_VAL(fcc->calling_scope->name), ZSTR_VAL(fcc->function_handler->common.function_name)); } } if (retval - && !(fcc->function_handler->common.fn_flags & ZEND_ACC_PUBLIC) - && !(check_flags & IS_CALLABLE_CHECK_NO_ACCESS)) { - scope = zend_get_executed_scope(); + && !(fcc->function_handler->common.fn_flags & ZEND_ACC_PUBLIC)) { + scope = get_scope(frame); if (fcc->function_handler->common.scope != scope) { if ((fcc->function_handler->common.fn_flags & ZEND_ACC_PRIVATE) || (!zend_check_protected(zend_get_function_root_class(fcc->function_handler), scope))) { @@ -3235,9 +3196,9 @@ get_function_via_handler: } } else if (error && !(check_flags & IS_CALLABLE_CHECK_SILENT)) { if (fcc->calling_scope) { - if (error) zend_spprintf(error, 0, "class '%s' does not have a method '%s'", ZSTR_VAL(fcc->calling_scope->name), ZSTR_VAL(mname)); + if (error) zend_spprintf(error, 0, "class %s does not have a method \"%s\"", ZSTR_VAL(fcc->calling_scope->name), ZSTR_VAL(mname)); } else { - if (error) zend_spprintf(error, 0, "function '%s' does not exist", ZSTR_VAL(mname)); + if (error) zend_spprintf(error, 0, "function %s() does not exist", ZSTR_VAL(mname)); } } zend_string_release_ex(lmname, 0); @@ -3246,7 +3207,7 @@ get_function_via_handler: if (fcc->object) { fcc->called_scope = fcc->object->ce; if (fcc->function_handler - && fcc->function_handler->common.fn_flags & ZEND_ACC_STATIC) { + && (fcc->function_handler->common.fn_flags & ZEND_ACC_STATIC)) { fcc->object = NULL; } } @@ -3254,25 +3215,13 @@ get_function_via_handler: } /* }}} */ -static zend_string *zend_create_method_string(zend_string *class_name, zend_string *method_name) { - zend_string *callable_name = zend_string_alloc( - ZSTR_LEN(class_name) + ZSTR_LEN(method_name) + sizeof("::") - 1, 0); - char *ptr = ZSTR_VAL(callable_name); - memcpy(ptr, ZSTR_VAL(class_name), ZSTR_LEN(class_name)); - ptr += ZSTR_LEN(class_name); - memcpy(ptr, "::", sizeof("::") - 1); - ptr += sizeof("::") - 1; - memcpy(ptr, ZSTR_VAL(method_name), ZSTR_LEN(method_name) + 1); - return callable_name; -} - ZEND_API zend_string *zend_get_callable_name_ex(zval *callable, zend_object *object) /* {{{ */ { try_again: switch (Z_TYPE_P(callable)) { case IS_STRING: if (object) { - return zend_create_method_string(object->ce->name, Z_STR_P(callable)); + return zend_create_member_string(object->ce->name, Z_STR_P(callable)); } return zend_string_copy(Z_STR_P(callable)); @@ -3291,28 +3240,19 @@ try_again: } if (Z_TYPE_P(obj) == IS_STRING) { - return zend_create_method_string(Z_STR_P(obj), Z_STR_P(method)); + return zend_create_member_string(Z_STR_P(obj), Z_STR_P(method)); } else if (Z_TYPE_P(obj) == IS_OBJECT) { - return zend_create_method_string(Z_OBJCE_P(obj)->name, Z_STR_P(method)); + return zend_create_member_string(Z_OBJCE_P(obj)->name, Z_STR_P(method)); } else { return ZSTR_KNOWN(ZEND_STR_ARRAY_CAPITALIZED); } } case IS_OBJECT: { - zend_class_entry *calling_scope; - zend_function *fptr; - zend_object *object; - if (Z_OBJ_HANDLER_P(callable, get_closure) - && Z_OBJ_HANDLER_P(callable, get_closure)(callable, &calling_scope, &fptr, &object) == SUCCESS) { - zend_class_entry *ce = Z_OBJCE_P(callable); - zend_string *callable_name = zend_string_alloc( - ZSTR_LEN(ce->name) + sizeof("::__invoke") - 1, 0); - memcpy(ZSTR_VAL(callable_name), ZSTR_VAL(ce->name), ZSTR_LEN(ce->name)); - memcpy(ZSTR_VAL(callable_name) + ZSTR_LEN(ce->name), "::__invoke", sizeof("::__invoke")); - return callable_name; - } - return zval_get_string(callable); + zend_class_entry *ce = Z_OBJCE_P(callable); + return zend_string_concat2( + ZSTR_VAL(ce->name), ZSTR_LEN(ce->name), + "::__invoke", sizeof("::__invoke") - 1); } case IS_REFERENCE: callable = Z_REFVAL_P(callable); @@ -3329,11 +3269,13 @@ ZEND_API zend_string *zend_get_callable_name(zval *callable) /* {{{ */ } /* }}} */ -static zend_always_inline zend_bool zend_is_callable_impl(zval *callable, zend_object *object, uint32_t check_flags, zend_fcall_info_cache *fcc, char **error) /* {{{ */ +static zend_always_inline zend_bool zend_is_callable_impl( + zval *callable, zend_object *object, zend_execute_data *frame, + uint32_t check_flags, zend_fcall_info_cache *fcc, char **error) /* {{{ */ { zend_bool ret; zend_fcall_info_cache fcc_local; - int strict_class = 0; + bool strict_class = 0; if (fcc == NULL) { fcc = &fcc_local; @@ -3361,7 +3303,7 @@ again: } check_func: - ret = zend_is_callable_check_func(check_flags, callable, fcc, strict_class, error); + ret = zend_is_callable_check_func(check_flags, callable, frame, fcc, strict_class, error); if (fcc == &fcc_local) { zend_release_fcall_info_cache(fcc); } @@ -3393,7 +3335,7 @@ check_func: return 1; } - if (!zend_is_callable_check_class(Z_STR_P(obj), zend_get_executed_scope(), fcc, &strict_class, error)) { + if (!zend_is_callable_check_class(Z_STR_P(obj), get_scope(frame), frame, fcc, &strict_class, error)) { return 0; } @@ -3429,17 +3371,12 @@ check_func: } return 0; case IS_OBJECT: - if (Z_OBJ_HANDLER_P(callable, get_closure)) { - if (Z_OBJ_HANDLER_P(callable, get_closure)(callable, &fcc->calling_scope, &fcc->function_handler, &fcc->object) == SUCCESS) { - fcc->called_scope = fcc->calling_scope; - if (fcc == &fcc_local) { - zend_release_fcall_info_cache(fcc); - } - return 1; - } else { - /* Discard exceptions thrown from Z_OBJ_HANDLER_P(callable, get_closure) */ - zend_clear_exception(); + if (Z_OBJ_HANDLER_P(callable, get_closure) && Z_OBJ_HANDLER_P(callable, get_closure)(Z_OBJ_P(callable), &fcc->calling_scope, &fcc->function_handler, &fcc->object, 1) == SUCCESS) { + fcc->called_scope = fcc->calling_scope; + if (fcc == &fcc_local) { + zend_release_fcall_info_cache(fcc); } + return 1; } if (error) *error = estrdup("no array or string given"); return 0; @@ -3455,7 +3392,13 @@ check_func: ZEND_API zend_bool zend_is_callable_ex(zval *callable, zend_object *object, uint32_t check_flags, zend_string **callable_name, zend_fcall_info_cache *fcc, char **error) /* {{{ */ { - zend_bool ret = zend_is_callable_impl(callable, object, check_flags, fcc, error); + /* Determine callability at the first parent user frame. */ + zend_execute_data *frame = EG(current_execute_data); + while (frame && (!frame->func || !ZEND_USER_CODE(frame->func->type))) { + frame = frame->prev_execute_data; + } + + zend_bool ret = zend_is_callable_impl(callable, object, frame, check_flags, fcc, error); if (callable_name) { *callable_name = zend_get_callable_name_ex(callable, object); } @@ -3472,7 +3415,7 @@ ZEND_API zend_bool zend_make_callable(zval *callable, zend_string **callable_nam { zend_fcall_info_cache fcc; - if (zend_is_callable_ex(callable, NULL, IS_CALLABLE_STRICT, callable_name, &fcc, NULL)) { + if (zend_is_callable_ex(callable, NULL, 0, callable_name, &fcc, NULL)) { if (Z_TYPE_P(callable) == IS_STRING && fcc.calling_scope) { zval_ptr_dtor_str(callable); array_init(callable); @@ -3486,7 +3429,7 @@ ZEND_API zend_bool zend_make_callable(zval *callable, zend_string **callable_nam } /* }}} */ -ZEND_API int zend_fcall_info_init(zval *callable, uint32_t check_flags, zend_fcall_info *fci, zend_fcall_info_cache *fcc, zend_string **callable_name, char **error) /* {{{ */ +ZEND_API zend_result zend_fcall_info_init(zval *callable, uint32_t check_flags, zend_fcall_info *fci, zend_fcall_info_cache *fcc, zend_string **callable_name, char **error) /* {{{ */ { if (!zend_is_callable_ex(callable, NULL, check_flags, callable_name, fcc, error)) { return FAILURE; @@ -3498,13 +3441,13 @@ ZEND_API int zend_fcall_info_init(zval *callable, uint32_t check_flags, zend_fca fci->retval = NULL; fci->param_count = 0; fci->params = NULL; - fci->no_separation = 1; + fci->named_params = NULL; return SUCCESS; } /* }}} */ -ZEND_API void zend_fcall_info_args_clear(zend_fcall_info *fci, int free_mem) /* {{{ */ +ZEND_API void zend_fcall_info_args_clear(zend_fcall_info *fci, bool free_mem) /* {{{ */ { if (fci->params) { zval *p = fci->params; @@ -3523,7 +3466,7 @@ ZEND_API void zend_fcall_info_args_clear(zend_fcall_info *fci, int free_mem) /* } /* }}} */ -ZEND_API void zend_fcall_info_args_save(zend_fcall_info *fci, int *param_count, zval **params) /* {{{ */ +ZEND_API void zend_fcall_info_args_save(zend_fcall_info *fci, uint32_t *param_count, zval **params) /* {{{ */ { *param_count = fci->param_count; *params = fci->params; @@ -3532,7 +3475,7 @@ ZEND_API void zend_fcall_info_args_save(zend_fcall_info *fci, int *param_count, } /* }}} */ -ZEND_API void zend_fcall_info_args_restore(zend_fcall_info *fci, int param_count, zval *params) /* {{{ */ +ZEND_API void zend_fcall_info_args_restore(zend_fcall_info *fci, uint32_t param_count, zval *params) /* {{{ */ { zend_fcall_info_args_clear(fci, 1); fci->param_count = param_count; @@ -3540,7 +3483,7 @@ ZEND_API void zend_fcall_info_args_restore(zend_fcall_info *fci, int param_count } /* }}} */ -ZEND_API int zend_fcall_info_args_ex(zend_fcall_info *fci, zend_function *func, zval *args) /* {{{ */ +ZEND_API zend_result zend_fcall_info_args_ex(zend_fcall_info *fci, zend_function *func, zval *args) /* {{{ */ { zval *arg, *params; uint32_t n = 1; @@ -3573,77 +3516,59 @@ ZEND_API int zend_fcall_info_args_ex(zend_fcall_info *fci, zend_function *func, } /* }}} */ -ZEND_API int zend_fcall_info_args(zend_fcall_info *fci, zval *args) /* {{{ */ +ZEND_API zend_result zend_fcall_info_args(zend_fcall_info *fci, zval *args) /* {{{ */ { return zend_fcall_info_args_ex(fci, NULL, args); } /* }}} */ -ZEND_API int zend_fcall_info_argp(zend_fcall_info *fci, int argc, zval *argv) /* {{{ */ +ZEND_API void zend_fcall_info_argp(zend_fcall_info *fci, uint32_t argc, zval *argv) /* {{{ */ { - int i; - - if (argc < 0) { - return FAILURE; - } - zend_fcall_info_args_clear(fci, !argc); if (argc) { fci->param_count = argc; fci->params = (zval *) erealloc(fci->params, fci->param_count * sizeof(zval)); - for (i = 0; i < argc; ++i) { + for (uint32_t i = 0; i < argc; ++i) { ZVAL_COPY(&fci->params[i], &argv[i]); } } - - return SUCCESS; } /* }}} */ -ZEND_API int zend_fcall_info_argv(zend_fcall_info *fci, int argc, va_list *argv) /* {{{ */ +ZEND_API void zend_fcall_info_argv(zend_fcall_info *fci, uint32_t argc, va_list *argv) /* {{{ */ { - int i; - zval *arg; - - if (argc < 0) { - return FAILURE; - } - zend_fcall_info_args_clear(fci, !argc); if (argc) { + zval *arg; fci->param_count = argc; fci->params = (zval *) erealloc(fci->params, fci->param_count * sizeof(zval)); - for (i = 0; i < argc; ++i) { + for (uint32_t i = 0; i < argc; ++i) { arg = va_arg(*argv, zval *); ZVAL_COPY(&fci->params[i], arg); } } - - return SUCCESS; } /* }}} */ -ZEND_API int zend_fcall_info_argn(zend_fcall_info *fci, int argc, ...) /* {{{ */ +ZEND_API void zend_fcall_info_argn(zend_fcall_info *fci, uint32_t argc, ...) /* {{{ */ { - int ret; va_list argv; va_start(argv, argc); - ret = zend_fcall_info_argv(fci, argc, &argv); + zend_fcall_info_argv(fci, argc, &argv); va_end(argv); - - return ret; } /* }}} */ -ZEND_API int zend_fcall_info_call(zend_fcall_info *fci, zend_fcall_info_cache *fcc, zval *retval_ptr, zval *args) /* {{{ */ +ZEND_API zend_result zend_fcall_info_call(zend_fcall_info *fci, zend_fcall_info_cache *fcc, zval *retval_ptr, zval *args) /* {{{ */ { zval retval, *org_params = NULL; - int result, org_count = 0; + uint32_t org_count = 0; + zend_result result; fci->retval = retval_ptr ? retval_ptr : &retval; if (args) { @@ -3691,7 +3616,7 @@ static zend_always_inline zend_bool is_persistent_class(zend_class_entry *ce) { && ce->info.internal.module->type == MODULE_PERSISTENT; } -ZEND_API int zend_declare_typed_property(zend_class_entry *ce, zend_string *name, zval *property, int access_type, zend_string *doc_comment, zend_type type) /* {{{ */ +ZEND_API zend_property_info *zend_declare_typed_property(zend_class_entry *ce, zend_string *name, zval *property, int access_type, zend_string *doc_comment, zend_type type) /* {{{ */ { zend_property_info *property_info, *property_info_ptr; @@ -3762,20 +3687,14 @@ ZEND_API int zend_declare_typed_property(zend_class_entry *ce, zend_string *name Z_PROP_FLAG_P(property_default_ptr) = Z_ISUNDEF_P(property) ? IS_PROP_UNINIT : 0; } if (ce->type & ZEND_INTERNAL_CLASS) { - switch(Z_TYPE_P(property)) { - case IS_ARRAY: - case IS_OBJECT: - case IS_RESOURCE: - zend_error_noreturn(E_CORE_ERROR, "Internal zval's can't be arrays, objects or resources"); - break; - default: - break; - } - /* Must be interned to avoid ZTS data races */ if (is_persistent_class(ce)) { name = zend_new_interned_string(zend_string_copy(name)); } + + if (Z_REFCOUNTED_P(property)) { + zend_error_noreturn(E_CORE_ERROR, "Internal zvals cannot be refcounted"); + } } if (access_type & ZEND_ACC_PUBLIC) { @@ -3790,16 +3709,17 @@ ZEND_API int zend_declare_typed_property(zend_class_entry *ce, zend_string *name property_info->name = zend_new_interned_string(property_info->name); property_info->flags = access_type; property_info->doc_comment = doc_comment; + property_info->attributes = NULL; property_info->ce = ce; property_info->type = type; zend_hash_update_ptr(&ce->properties_info, name, property_info); - return SUCCESS; + return property_info; } /* }}} */ -ZEND_API int zend_try_assign_typed_ref_ex(zend_reference *ref, zval *val, zend_bool strict) /* {{{ */ +ZEND_API zend_result zend_try_assign_typed_ref_ex(zend_reference *ref, zval *val, zend_bool strict) /* {{{ */ { if (UNEXPECTED(!zend_verify_ref_assignable_zval(ref, val, strict))) { zval_ptr_dtor(val); @@ -3812,13 +3732,13 @@ ZEND_API int zend_try_assign_typed_ref_ex(zend_reference *ref, zval *val, zend_b } /* }}} */ -ZEND_API int zend_try_assign_typed_ref(zend_reference *ref, zval *val) /* {{{ */ +ZEND_API zend_result zend_try_assign_typed_ref(zend_reference *ref, zval *val) /* {{{ */ { return zend_try_assign_typed_ref_ex(ref, val, ZEND_ARG_USES_STRICT_TYPES()); } /* }}} */ -ZEND_API int zend_try_assign_typed_ref_null(zend_reference *ref) /* {{{ */ +ZEND_API zend_result zend_try_assign_typed_ref_null(zend_reference *ref) /* {{{ */ { zval tmp; @@ -3827,7 +3747,7 @@ ZEND_API int zend_try_assign_typed_ref_null(zend_reference *ref) /* {{{ */ } /* }}} */ -ZEND_API int zend_try_assign_typed_ref_bool(zend_reference *ref, zend_bool val) /* {{{ */ +ZEND_API zend_result zend_try_assign_typed_ref_bool(zend_reference *ref, zend_bool val) /* {{{ */ { zval tmp; @@ -3836,7 +3756,7 @@ ZEND_API int zend_try_assign_typed_ref_bool(zend_reference *ref, zend_bool val) } /* }}} */ -ZEND_API int zend_try_assign_typed_ref_long(zend_reference *ref, zend_long lval) /* {{{ */ +ZEND_API zend_result zend_try_assign_typed_ref_long(zend_reference *ref, zend_long lval) /* {{{ */ { zval tmp; @@ -3845,7 +3765,7 @@ ZEND_API int zend_try_assign_typed_ref_long(zend_reference *ref, zend_long lval) } /* }}} */ -ZEND_API int zend_try_assign_typed_ref_double(zend_reference *ref, double dval) /* {{{ */ +ZEND_API zend_result zend_try_assign_typed_ref_double(zend_reference *ref, double dval) /* {{{ */ { zval tmp; @@ -3854,7 +3774,7 @@ ZEND_API int zend_try_assign_typed_ref_double(zend_reference *ref, double dval) } /* }}} */ -ZEND_API int zend_try_assign_typed_ref_empty_string(zend_reference *ref) /* {{{ */ +ZEND_API zend_result zend_try_assign_typed_ref_empty_string(zend_reference *ref) /* {{{ */ { zval tmp; @@ -3863,7 +3783,7 @@ ZEND_API int zend_try_assign_typed_ref_empty_string(zend_reference *ref) /* {{{ } /* }}} */ -ZEND_API int zend_try_assign_typed_ref_str(zend_reference *ref, zend_string *str) /* {{{ */ +ZEND_API zend_result zend_try_assign_typed_ref_str(zend_reference *ref, zend_string *str) /* {{{ */ { zval tmp; @@ -3872,7 +3792,7 @@ ZEND_API int zend_try_assign_typed_ref_str(zend_reference *ref, zend_string *str } /* }}} */ -ZEND_API int zend_try_assign_typed_ref_string(zend_reference *ref, const char *string) /* {{{ */ +ZEND_API zend_result zend_try_assign_typed_ref_string(zend_reference *ref, const char *string) /* {{{ */ { zval tmp; @@ -3881,7 +3801,7 @@ ZEND_API int zend_try_assign_typed_ref_string(zend_reference *ref, const char *s } /* }}} */ -ZEND_API int zend_try_assign_typed_ref_stringl(zend_reference *ref, const char *string, size_t len) /* {{{ */ +ZEND_API zend_result zend_try_assign_typed_ref_stringl(zend_reference *ref, const char *string, size_t len) /* {{{ */ { zval tmp; @@ -3890,7 +3810,7 @@ ZEND_API int zend_try_assign_typed_ref_stringl(zend_reference *ref, const char * } /* }}} */ -ZEND_API int zend_try_assign_typed_ref_arr(zend_reference *ref, zend_array *arr) /* {{{ */ +ZEND_API zend_result zend_try_assign_typed_ref_arr(zend_reference *ref, zend_array *arr) /* {{{ */ { zval tmp; @@ -3899,7 +3819,7 @@ ZEND_API int zend_try_assign_typed_ref_arr(zend_reference *ref, zend_array *arr) } /* }}} */ -ZEND_API int zend_try_assign_typed_ref_res(zend_reference *ref, zend_resource *res) /* {{{ */ +ZEND_API zend_result zend_try_assign_typed_ref_res(zend_reference *ref, zend_resource *res) /* {{{ */ { zval tmp; @@ -3908,7 +3828,7 @@ ZEND_API int zend_try_assign_typed_ref_res(zend_reference *ref, zend_resource *r } /* }}} */ -ZEND_API int zend_try_assign_typed_ref_zval(zend_reference *ref, zval *zv) /* {{{ */ +ZEND_API zend_result zend_try_assign_typed_ref_zval(zend_reference *ref, zval *zv) /* {{{ */ { zval tmp; @@ -3917,7 +3837,7 @@ ZEND_API int zend_try_assign_typed_ref_zval(zend_reference *ref, zval *zv) /* {{ } /* }}} */ -ZEND_API int zend_try_assign_typed_ref_zval_ex(zend_reference *ref, zval *zv, zend_bool strict) /* {{{ */ +ZEND_API zend_result zend_try_assign_typed_ref_zval_ex(zend_reference *ref, zval *zv, zend_bool strict) /* {{{ */ { zval tmp; @@ -3926,76 +3846,75 @@ ZEND_API int zend_try_assign_typed_ref_zval_ex(zend_reference *ref, zval *zv, ze } /* }}} */ -ZEND_API int zend_declare_property_ex(zend_class_entry *ce, zend_string *name, zval *property, int access_type, zend_string *doc_comment) /* {{{ */ +ZEND_API void zend_declare_property_ex(zend_class_entry *ce, zend_string *name, zval *property, int access_type, zend_string *doc_comment) /* {{{ */ { - return zend_declare_typed_property(ce, name, property, access_type, doc_comment, 0); + zend_declare_typed_property(ce, name, property, access_type, doc_comment, (zend_type) ZEND_TYPE_INIT_NONE(0)); } /* }}} */ -ZEND_API int zend_declare_property(zend_class_entry *ce, const char *name, size_t name_length, zval *property, int access_type) /* {{{ */ +ZEND_API void zend_declare_property(zend_class_entry *ce, const char *name, size_t name_length, zval *property, int access_type) /* {{{ */ { zend_string *key = zend_string_init(name, name_length, is_persistent_class(ce)); - int ret = zend_declare_property_ex(ce, key, property, access_type, NULL); + zend_declare_property_ex(ce, key, property, access_type, NULL); zend_string_release(key); - return ret; } /* }}} */ -ZEND_API int zend_declare_property_null(zend_class_entry *ce, const char *name, size_t name_length, int access_type) /* {{{ */ +ZEND_API void zend_declare_property_null(zend_class_entry *ce, const char *name, size_t name_length, int access_type) /* {{{ */ { zval property; ZVAL_NULL(&property); - return zend_declare_property(ce, name, name_length, &property, access_type); + zend_declare_property(ce, name, name_length, &property, access_type); } /* }}} */ -ZEND_API int zend_declare_property_bool(zend_class_entry *ce, const char *name, size_t name_length, zend_long value, int access_type) /* {{{ */ +ZEND_API void zend_declare_property_bool(zend_class_entry *ce, const char *name, size_t name_length, zend_long value, int access_type) /* {{{ */ { zval property; ZVAL_BOOL(&property, value); - return zend_declare_property(ce, name, name_length, &property, access_type); + zend_declare_property(ce, name, name_length, &property, access_type); } /* }}} */ -ZEND_API int zend_declare_property_long(zend_class_entry *ce, const char *name, size_t name_length, zend_long value, int access_type) /* {{{ */ +ZEND_API void zend_declare_property_long(zend_class_entry *ce, const char *name, size_t name_length, zend_long value, int access_type) /* {{{ */ { zval property; ZVAL_LONG(&property, value); - return zend_declare_property(ce, name, name_length, &property, access_type); + zend_declare_property(ce, name, name_length, &property, access_type); } /* }}} */ -ZEND_API int zend_declare_property_double(zend_class_entry *ce, const char *name, size_t name_length, double value, int access_type) /* {{{ */ +ZEND_API void zend_declare_property_double(zend_class_entry *ce, const char *name, size_t name_length, double value, int access_type) /* {{{ */ { zval property; ZVAL_DOUBLE(&property, value); - return zend_declare_property(ce, name, name_length, &property, access_type); + zend_declare_property(ce, name, name_length, &property, access_type); } /* }}} */ -ZEND_API int zend_declare_property_string(zend_class_entry *ce, const char *name, size_t name_length, const char *value, int access_type) /* {{{ */ +ZEND_API void zend_declare_property_string(zend_class_entry *ce, const char *name, size_t name_length, const char *value, int access_type) /* {{{ */ { zval property; ZVAL_NEW_STR(&property, zend_string_init(value, strlen(value), ce->type & ZEND_INTERNAL_CLASS)); - return zend_declare_property(ce, name, name_length, &property, access_type); + zend_declare_property(ce, name, name_length, &property, access_type); } /* }}} */ -ZEND_API int zend_declare_property_stringl(zend_class_entry *ce, const char *name, size_t name_length, const char *value, size_t value_len, int access_type) /* {{{ */ +ZEND_API void zend_declare_property_stringl(zend_class_entry *ce, const char *name, size_t name_length, const char *value, size_t value_len, int access_type) /* {{{ */ { zval property; ZVAL_NEW_STR(&property, zend_string_init(value, value_len, ce->type & ZEND_INTERNAL_CLASS)); - return zend_declare_property(ce, name, name_length, &property, access_type); + zend_declare_property(ce, name, name_length, &property, access_type); } /* }}} */ -ZEND_API int zend_declare_class_constant_ex(zend_class_entry *ce, zend_string *name, zval *value, int access_type, zend_string *doc_comment) /* {{{ */ +ZEND_API zend_class_constant *zend_declare_class_constant_ex(zend_class_entry *ce, zend_string *name, zval *value, int access_type, zend_string *doc_comment) /* {{{ */ { zend_class_constant *c; @@ -4022,6 +3941,7 @@ ZEND_API int zend_declare_class_constant_ex(zend_class_entry *ce, zend_string *n ZVAL_COPY_VALUE(&c->value, value); Z_ACCESS_FLAGS(c->value) = access_type; c->doc_comment = doc_comment; + c->attributes = NULL; c->ce = ce; if (Z_TYPE_P(value) == IS_CONSTANT_AST) { ce->ce_flags &= ~ZEND_ACC_CONSTANTS_UPDATED; @@ -4032,14 +3952,12 @@ ZEND_API int zend_declare_class_constant_ex(zend_class_entry *ce, zend_string *n "Cannot redefine class constant %s::%s", ZSTR_VAL(ce->name), ZSTR_VAL(name)); } - return SUCCESS; + return c; } /* }}} */ -ZEND_API int zend_declare_class_constant(zend_class_entry *ce, const char *name, size_t name_length, zval *value) /* {{{ */ +ZEND_API void zend_declare_class_constant(zend_class_entry *ce, const char *name, size_t name_length, zval *value) /* {{{ */ { - int ret; - zend_string *key; if (ce->type == ZEND_INTERNAL_CLASS) { @@ -4047,93 +3965,90 @@ ZEND_API int zend_declare_class_constant(zend_class_entry *ce, const char *name, } else { key = zend_string_init(name, name_length, 0); } - ret = zend_declare_class_constant_ex(ce, key, value, ZEND_ACC_PUBLIC, NULL); + zend_declare_class_constant_ex(ce, key, value, ZEND_ACC_PUBLIC, NULL); zend_string_release(key); - return ret; } /* }}} */ -ZEND_API int zend_declare_class_constant_null(zend_class_entry *ce, const char *name, size_t name_length) /* {{{ */ +ZEND_API void zend_declare_class_constant_null(zend_class_entry *ce, const char *name, size_t name_length) /* {{{ */ { zval constant; ZVAL_NULL(&constant); - return zend_declare_class_constant(ce, name, name_length, &constant); + zend_declare_class_constant(ce, name, name_length, &constant); } /* }}} */ -ZEND_API int zend_declare_class_constant_long(zend_class_entry *ce, const char *name, size_t name_length, zend_long value) /* {{{ */ +ZEND_API void zend_declare_class_constant_long(zend_class_entry *ce, const char *name, size_t name_length, zend_long value) /* {{{ */ { zval constant; ZVAL_LONG(&constant, value); - return zend_declare_class_constant(ce, name, name_length, &constant); + zend_declare_class_constant(ce, name, name_length, &constant); } /* }}} */ -ZEND_API int zend_declare_class_constant_bool(zend_class_entry *ce, const char *name, size_t name_length, zend_bool value) /* {{{ */ +ZEND_API void zend_declare_class_constant_bool(zend_class_entry *ce, const char *name, size_t name_length, zend_bool value) /* {{{ */ { zval constant; ZVAL_BOOL(&constant, value); - return zend_declare_class_constant(ce, name, name_length, &constant); + zend_declare_class_constant(ce, name, name_length, &constant); } /* }}} */ -ZEND_API int zend_declare_class_constant_double(zend_class_entry *ce, const char *name, size_t name_length, double value) /* {{{ */ +ZEND_API void zend_declare_class_constant_double(zend_class_entry *ce, const char *name, size_t name_length, double value) /* {{{ */ { zval constant; ZVAL_DOUBLE(&constant, value); - return zend_declare_class_constant(ce, name, name_length, &constant); + zend_declare_class_constant(ce, name, name_length, &constant); } /* }}} */ -ZEND_API int zend_declare_class_constant_stringl(zend_class_entry *ce, const char *name, size_t name_length, const char *value, size_t value_length) /* {{{ */ +ZEND_API void zend_declare_class_constant_stringl(zend_class_entry *ce, const char *name, size_t name_length, const char *value, size_t value_length) /* {{{ */ { zval constant; ZVAL_NEW_STR(&constant, zend_string_init(value, value_length, ce->type & ZEND_INTERNAL_CLASS)); - return zend_declare_class_constant(ce, name, name_length, &constant); + zend_declare_class_constant(ce, name, name_length, &constant); } /* }}} */ -ZEND_API int zend_declare_class_constant_string(zend_class_entry *ce, const char *name, size_t name_length, const char *value) /* {{{ */ +ZEND_API void zend_declare_class_constant_string(zend_class_entry *ce, const char *name, size_t name_length, const char *value) /* {{{ */ { - return zend_declare_class_constant_stringl(ce, name, name_length, value, strlen(value)); + zend_declare_class_constant_stringl(ce, name, name_length, value, strlen(value)); } /* }}} */ -ZEND_API void zend_update_property_ex(zend_class_entry *scope, zval *object, zend_string *name, zval *value) /* {{{ */ +ZEND_API void zend_update_property_ex(zend_class_entry *scope, zend_object *object, zend_string *name, zval *value) /* {{{ */ { - zval property; zend_class_entry *old_scope = EG(fake_scope); EG(fake_scope) = scope; - ZVAL_STR(&property, name); - Z_OBJ_HT_P(object)->write_property(object, &property, value, NULL); + object->handlers->write_property(object, name, value, NULL); EG(fake_scope) = old_scope; } /* }}} */ -ZEND_API void zend_update_property(zend_class_entry *scope, zval *object, const char *name, size_t name_length, zval *value) /* {{{ */ +ZEND_API void zend_update_property(zend_class_entry *scope, zend_object *object, const char *name, size_t name_length, zval *value) /* {{{ */ { - zval property; + zend_string *property; zend_class_entry *old_scope = EG(fake_scope); EG(fake_scope) = scope; - ZVAL_STRINGL(&property, name, name_length); - Z_OBJ_HT_P(object)->write_property(object, &property, value, NULL); - zval_ptr_dtor(&property); + property = zend_string_init(name, name_length, 0); + object->handlers->write_property(object, property, value, NULL); + zend_string_release_ex(property, 0); EG(fake_scope) = old_scope; } /* }}} */ -ZEND_API void zend_update_property_null(zend_class_entry *scope, zval *object, const char *name, size_t name_length) /* {{{ */ +ZEND_API void zend_update_property_null(zend_class_entry *scope, zend_object *object, const char *name, size_t name_length) /* {{{ */ { zval tmp; @@ -4142,22 +4057,22 @@ ZEND_API void zend_update_property_null(zend_class_entry *scope, zval *object, c } /* }}} */ -ZEND_API void zend_unset_property(zend_class_entry *scope, zval *object, const char *name, size_t name_length) /* {{{ */ +ZEND_API void zend_unset_property(zend_class_entry *scope, zend_object *object, const char *name, size_t name_length) /* {{{ */ { - zval property; + zend_string *property; zend_class_entry *old_scope = EG(fake_scope); EG(fake_scope) = scope; - ZVAL_STRINGL(&property, name, name_length); - Z_OBJ_HT_P(object)->unset_property(object, &property, 0); - zval_ptr_dtor(&property); + property = zend_string_init(name, name_length, 0); + object->handlers->unset_property(object, property, 0); + zend_string_release_ex(property, 0); EG(fake_scope) = old_scope; } /* }}} */ -ZEND_API void zend_update_property_bool(zend_class_entry *scope, zval *object, const char *name, size_t name_length, zend_long value) /* {{{ */ +ZEND_API void zend_update_property_bool(zend_class_entry *scope, zend_object *object, const char *name, size_t name_length, zend_long value) /* {{{ */ { zval tmp; @@ -4166,7 +4081,7 @@ ZEND_API void zend_update_property_bool(zend_class_entry *scope, zval *object, c } /* }}} */ -ZEND_API void zend_update_property_long(zend_class_entry *scope, zval *object, const char *name, size_t name_length, zend_long value) /* {{{ */ +ZEND_API void zend_update_property_long(zend_class_entry *scope, zend_object *object, const char *name, size_t name_length, zend_long value) /* {{{ */ { zval tmp; @@ -4175,7 +4090,7 @@ ZEND_API void zend_update_property_long(zend_class_entry *scope, zval *object, c } /* }}} */ -ZEND_API void zend_update_property_double(zend_class_entry *scope, zval *object, const char *name, size_t name_length, double value) /* {{{ */ +ZEND_API void zend_update_property_double(zend_class_entry *scope, zend_object *object, const char *name, size_t name_length, double value) /* {{{ */ { zval tmp; @@ -4184,7 +4099,7 @@ ZEND_API void zend_update_property_double(zend_class_entry *scope, zval *object, } /* }}} */ -ZEND_API void zend_update_property_str(zend_class_entry *scope, zval *object, const char *name, size_t name_length, zend_string *value) /* {{{ */ +ZEND_API void zend_update_property_str(zend_class_entry *scope, zend_object *object, const char *name, size_t name_length, zend_string *value) /* {{{ */ { zval tmp; @@ -4193,7 +4108,7 @@ ZEND_API void zend_update_property_str(zend_class_entry *scope, zval *object, co } /* }}} */ -ZEND_API void zend_update_property_string(zend_class_entry *scope, zval *object, const char *name, size_t name_length, const char *value) /* {{{ */ +ZEND_API void zend_update_property_string(zend_class_entry *scope, zend_object *object, const char *name, size_t name_length, const char *value) /* {{{ */ { zval tmp; @@ -4203,7 +4118,7 @@ ZEND_API void zend_update_property_string(zend_class_entry *scope, zval *object, } /* }}} */ -ZEND_API void zend_update_property_stringl(zend_class_entry *scope, zval *object, const char *name, size_t name_length, const char *value, size_t value_len) /* {{{ */ +ZEND_API void zend_update_property_stringl(zend_class_entry *scope, zend_object *object, const char *name, size_t name_length, const char *value, size_t value_len) /* {{{ */ { zval tmp; @@ -4213,7 +4128,7 @@ ZEND_API void zend_update_property_stringl(zend_class_entry *scope, zval *object } /* }}} */ -ZEND_API int zend_update_static_property_ex(zend_class_entry *scope, zend_string *name, zval *value) /* {{{ */ +ZEND_API zend_result zend_update_static_property_ex(zend_class_entry *scope, zend_string *name, zval *value) /* {{{ */ { zval *property, tmp; zend_property_info *prop_info; @@ -4235,7 +4150,7 @@ ZEND_API int zend_update_static_property_ex(zend_class_entry *scope, zend_string ZEND_ASSERT(!Z_ISREF_P(value)); Z_TRY_ADDREF_P(value); - if (prop_info->type) { + if (ZEND_TYPE_IS_SET(prop_info->type)) { ZVAL_COPY_VALUE(&tmp, value); if (!zend_verify_property_type(prop_info, &tmp, /* strict */ 0)) { Z_TRY_DELREF_P(value); @@ -4249,16 +4164,16 @@ ZEND_API int zend_update_static_property_ex(zend_class_entry *scope, zend_string } /* }}} */ -ZEND_API int zend_update_static_property(zend_class_entry *scope, const char *name, size_t name_length, zval *value) /* {{{ */ +ZEND_API zend_result zend_update_static_property(zend_class_entry *scope, const char *name, size_t name_length, zval *value) /* {{{ */ { zend_string *key = zend_string_init(name, name_length, 0); - int retval = zend_update_static_property_ex(scope, key, value); + bool retval = zend_update_static_property_ex(scope, key, value); zend_string_efree(key); return retval; } /* }}} */ -ZEND_API int zend_update_static_property_null(zend_class_entry *scope, const char *name, size_t name_length) /* {{{ */ +ZEND_API zend_result zend_update_static_property_null(zend_class_entry *scope, const char *name, size_t name_length) /* {{{ */ { zval tmp; @@ -4267,7 +4182,7 @@ ZEND_API int zend_update_static_property_null(zend_class_entry *scope, const cha } /* }}} */ -ZEND_API int zend_update_static_property_bool(zend_class_entry *scope, const char *name, size_t name_length, zend_long value) /* {{{ */ +ZEND_API zend_result zend_update_static_property_bool(zend_class_entry *scope, const char *name, size_t name_length, zend_long value) /* {{{ */ { zval tmp; @@ -4276,7 +4191,7 @@ ZEND_API int zend_update_static_property_bool(zend_class_entry *scope, const cha } /* }}} */ -ZEND_API int zend_update_static_property_long(zend_class_entry *scope, const char *name, size_t name_length, zend_long value) /* {{{ */ +ZEND_API zend_result zend_update_static_property_long(zend_class_entry *scope, const char *name, size_t name_length, zend_long value) /* {{{ */ { zval tmp; @@ -4285,7 +4200,7 @@ ZEND_API int zend_update_static_property_long(zend_class_entry *scope, const cha } /* }}} */ -ZEND_API int zend_update_static_property_double(zend_class_entry *scope, const char *name, size_t name_length, double value) /* {{{ */ +ZEND_API zend_result zend_update_static_property_double(zend_class_entry *scope, const char *name, size_t name_length, double value) /* {{{ */ { zval tmp; @@ -4294,7 +4209,7 @@ ZEND_API int zend_update_static_property_double(zend_class_entry *scope, const c } /* }}} */ -ZEND_API int zend_update_static_property_string(zend_class_entry *scope, const char *name, size_t name_length, const char *value) /* {{{ */ +ZEND_API zend_result zend_update_static_property_string(zend_class_entry *scope, const char *name, size_t name_length, const char *value) /* {{{ */ { zval tmp; @@ -4304,7 +4219,7 @@ ZEND_API int zend_update_static_property_string(zend_class_entry *scope, const c } /* }}} */ -ZEND_API int zend_update_static_property_stringl(zend_class_entry *scope, const char *name, size_t name_length, const char *value, size_t value_len) /* {{{ */ +ZEND_API zend_result zend_update_static_property_stringl(zend_class_entry *scope, const char *name, size_t name_length, const char *value, size_t value_len) /* {{{ */ { zval tmp; @@ -4314,22 +4229,21 @@ ZEND_API int zend_update_static_property_stringl(zend_class_entry *scope, const } /* }}} */ -ZEND_API zval *zend_read_property_ex(zend_class_entry *scope, zval *object, zend_string *name, zend_bool silent, zval *rv) /* {{{ */ +ZEND_API zval *zend_read_property_ex(zend_class_entry *scope, zend_object *object, zend_string *name, zend_bool silent, zval *rv) /* {{{ */ { - zval property, *value; + zval *value; zend_class_entry *old_scope = EG(fake_scope); EG(fake_scope) = scope; - ZVAL_STR(&property, name); - value = Z_OBJ_HT_P(object)->read_property(object, &property, silent?BP_VAR_IS:BP_VAR_R, NULL, rv); + value = object->handlers->read_property(object, name, silent?BP_VAR_IS:BP_VAR_R, NULL, rv); EG(fake_scope) = old_scope; return value; } /* }}} */ -ZEND_API zval *zend_read_property(zend_class_entry *scope, zval *object, const char *name, size_t name_length, zend_bool silent, zval *rv) /* {{{ */ +ZEND_API zval *zend_read_property(zend_class_entry *scope, zend_object *object, const char *name, size_t name_length, zend_bool silent, zval *rv) /* {{{ */ { zval *value; zend_string *str; @@ -4367,7 +4281,6 @@ ZEND_API void zend_save_error_handling(zend_error_handling *current) /* {{{ */ { current->handling = EG(error_handling); current->exception = EG(exception_class); - ZVAL_UNDEF(¤t->user_handler); } /* }}} */ @@ -4389,55 +4302,6 @@ ZEND_API void zend_restore_error_handling(zend_error_handling *saved) /* {{{ */ } /* }}} */ -ZEND_API zend_string* zend_find_alias_name(zend_class_entry *ce, zend_string *name) /* {{{ */ -{ - zend_trait_alias *alias, **alias_ptr; - - if ((alias_ptr = ce->trait_aliases)) { - alias = *alias_ptr; - while (alias) { - if (alias->alias && zend_string_equals_ci(alias->alias, name)) { - return alias->alias; - } - alias_ptr++; - alias = *alias_ptr; - } - } - - return name; -} -/* }}} */ - -ZEND_API zend_string *zend_resolve_method_name(zend_class_entry *ce, zend_function *f) /* {{{ */ -{ - zend_function *func; - HashTable *function_table; - zend_string *name; - - if (f->common.type != ZEND_USER_FUNCTION || - (f->op_array.refcount && *(f->op_array.refcount) < 2) || - !f->common.scope || - !f->common.scope->trait_aliases) { - return f->common.function_name; - } - - function_table = &ce->function_table; - ZEND_HASH_FOREACH_STR_KEY_PTR(function_table, name, func) { - if (func == f) { - if (!name) { - return f->common.function_name; - } - if (ZSTR_LEN(name) == ZSTR_LEN(f->common.function_name) && - !strncasecmp(ZSTR_VAL(name), ZSTR_VAL(f->common.function_name), ZSTR_LEN(f->common.function_name))) { - return f->common.function_name; - } - return zend_find_alias_name(f->common.scope, name); - } - } ZEND_HASH_FOREACH_END(); - return f->common.function_name; -} -/* }}} */ - ZEND_API ZEND_COLD const char *zend_get_object_type(const zend_class_entry *ce) /* {{{ */ { if(ce->ce_flags & ZEND_ACC_TRAIT) { @@ -4456,7 +4320,7 @@ ZEND_API zend_bool zend_is_iterable(zval *iterable) /* {{{ */ case IS_ARRAY: return 1; case IS_OBJECT: - return instanceof_function(Z_OBJCE_P(iterable), zend_ce_traversable); + return zend_class_implements_interface(Z_OBJCE_P(iterable), zend_ce_traversable); default: return 0; } @@ -4473,9 +4337,104 @@ ZEND_API zend_bool zend_is_countable(zval *countable) /* {{{ */ return 1; } - return instanceof_function(Z_OBJCE_P(countable), zend_ce_countable); + return zend_class_implements_interface(Z_OBJCE_P(countable), zend_ce_countable); default: return 0; } } /* }}} */ + +static zend_result get_default_via_ast(zval *default_value_zval, const char *default_value) { + zend_ast *ast; + zend_arena *ast_arena; + + zend_string *code = zend_string_concat3( + "<?php ", sizeof("<?php ") - 1, default_value, strlen(default_value), ";", 1); + + ast = zend_compile_string_to_ast(code, &ast_arena, ""); + zend_string_release(code); + + if (!ast) { + return FAILURE; + } + + zend_ast_list *statement_list = zend_ast_get_list(ast); + zend_ast *const_expression_ast = statement_list->child[0]; + + zend_arena *original_ast_arena = CG(ast_arena); + uint32_t original_compiler_options = CG(compiler_options); + zend_file_context original_file_context; + CG(ast_arena) = ast_arena; + /* Disable constant substitution, to make getDefaultValueConstant() work. */ + CG(compiler_options) |= ZEND_COMPILE_NO_CONSTANT_SUBSTITUTION | ZEND_COMPILE_NO_PERSISTENT_CONSTANT_SUBSTITUTION; + zend_file_context_begin(&original_file_context); + zend_const_expr_to_zval(default_value_zval, const_expression_ast); + CG(ast_arena) = original_ast_arena; + CG(compiler_options) = original_compiler_options; + zend_file_context_end(&original_file_context); + + zend_ast_destroy(ast); + zend_arena_destroy(ast_arena); + + return SUCCESS; +} + +static zend_string *try_parse_string(const char *str, size_t len, char quote) { + if (len == 0) { + return ZSTR_EMPTY_ALLOC(); + } + + for (size_t i = 0; i < len; i++) { + if (str[i] == '\\' || str[i] == quote) { + return NULL; + } + } + return zend_string_init(str, len, 0); +} + +ZEND_API zend_result zend_get_default_from_internal_arg_info( + zval *default_value_zval, zend_internal_arg_info *arg_info) +{ + const char *default_value = arg_info->default_value; + if (!default_value) { + return FAILURE; + } + + /* Avoid going through the full AST machinery for some simple and common cases. */ + size_t default_value_len = strlen(default_value); + zend_ulong lval; + if (default_value_len == sizeof("null")-1 + && !memcmp(default_value, "null", sizeof("null")-1)) { + ZVAL_NULL(default_value_zval); + return SUCCESS; + } else if (default_value_len == sizeof("true")-1 + && !memcmp(default_value, "true", sizeof("true")-1)) { + ZVAL_TRUE(default_value_zval); + return SUCCESS; + } else if (default_value_len == sizeof("false")-1 + && !memcmp(default_value, "false", sizeof("false")-1)) { + ZVAL_FALSE(default_value_zval); + return SUCCESS; + } else if (default_value_len >= 2 + && (default_value[0] == '\'' || default_value[0] == '"') + && default_value[default_value_len - 1] == default_value[0]) { + zend_string *str = try_parse_string( + default_value + 1, default_value_len - 2, default_value[0]); + if (str) { + ZVAL_STR(default_value_zval, str); + return SUCCESS; + } + } else if (default_value_len == sizeof("[]")-1 + && !memcmp(default_value, "[]", sizeof("[]")-1)) { + ZVAL_EMPTY_ARRAY(default_value_zval); + return SUCCESS; + } else if (ZEND_HANDLE_NUMERIC_STR(default_value, default_value_len, lval)) { + ZVAL_LONG(default_value_zval, lval); + return SUCCESS; + } + +#if 0 + fprintf(stderr, "Evaluating %s via AST\n", default_value); +#endif + return get_default_via_ast(default_value_zval, default_value); +} |