diff options
Diffstat (limited to 'Zend/zend_builtin_functions.c')
-rw-r--r-- | Zend/zend_builtin_functions.c | 227 |
1 files changed, 162 insertions, 65 deletions
diff --git a/Zend/zend_builtin_functions.c b/Zend/zend_builtin_functions.c index 6a0970d373..c84a1f1bcd 100644 --- a/Zend/zend_builtin_functions.c +++ b/Zend/zend_builtin_functions.c @@ -31,6 +31,12 @@ #undef ZEND_TEST_EXCEPTIONS +#if ZEND_DEBUG +static zend_class_entry *zend_test_interface; +static zend_class_entry *zend_test_class; +static zend_object_handlers zend_test_class_handlers; +#endif + static ZEND_FUNCTION(zend_version); static ZEND_FUNCTION(func_num_args); static ZEND_FUNCTION(func_get_arg); @@ -257,6 +263,51 @@ ZEND_END_ARG_INFO() /* }}} */ +#if ZEND_DEBUG +static zend_object *zend_test_class_new(zend_class_entry *class_type) /* {{{ */ { + zend_object *obj = zend_objects_new(class_type); + obj->handlers = &zend_test_class_handlers; + return obj; +} +/* }}} */ + +static zend_function *zend_test_class_method_get(zend_object **object, zend_string *name, const zval *key) /* {{{ */ { + zend_internal_function *fptr = emalloc(sizeof(zend_internal_function)); + fptr->type = ZEND_OVERLOADED_FUNCTION_TEMPORARY; + fptr->num_args = 1; + fptr->arg_info = NULL; + fptr->scope = (*object)->ce; + fptr->fn_flags = ZEND_ACC_CALL_VIA_HANDLER; + fptr->function_name = zend_string_copy(name); + fptr->handler = ZEND_FN(zend_test_func); + zend_set_function_arg_flags((zend_function*)fptr); + + return (zend_function*)fptr; +} +/* }}} */ + +static zend_function *zend_test_class_static_method_get(zend_class_entry *ce, zend_string *name) /* {{{ */ { + zend_internal_function *fptr = emalloc(sizeof(zend_internal_function)); + fptr->type = ZEND_OVERLOADED_FUNCTION; + fptr->num_args = 1; + fptr->arg_info = NULL; + fptr->scope = ce; + fptr->fn_flags = ZEND_ACC_CALL_VIA_HANDLER|ZEND_ACC_STATIC; + fptr->function_name = name; + fptr->handler = ZEND_FN(zend_test_func); + zend_set_function_arg_flags((zend_function*)fptr); + + return (zend_function*)fptr; +} +/* }}} */ + +static int zend_test_class_call_method(zend_string *method, zend_object *object, INTERNAL_FUNCTION_PARAMETERS) /* {{{ */ { + RETVAL_STR(zend_string_copy(method)); + return 0; +} +/* }}} */ +#endif + static const zend_function_entry builtin_functions[] = { /* {{{ */ ZEND_FE(zend_version, arginfo_zend__void) ZEND_FE(func_num_args, arginfo_zend__void) @@ -339,6 +390,21 @@ ZEND_MINIT_FUNCTION(core) { /* {{{ */ zend_register_default_classes(); +#if ZEND_DEBUG + INIT_CLASS_ENTRY(class_entry, "_ZendTestInterface", NULL); + zend_test_interface = zend_register_internal_interface(&class_entry); + zend_declare_class_constant_long(zend_test_interface, ZEND_STRL("DUMMY"), 0); + INIT_CLASS_ENTRY(class_entry, "_ZendTestClass", NULL); + zend_test_class = zend_register_internal_class_ex(&class_entry, NULL); + zend_class_implements(zend_test_class, 1, zend_test_interface); + zend_test_class->create_object = zend_test_class_new; + zend_test_class->get_static_method = zend_test_class_static_method_get; + + memcpy(&zend_test_class_handlers, zend_get_std_object_handlers(), sizeof(zend_object_handlers)); + zend_test_class_handlers.get_method = zend_test_class_method_get; + zend_test_class_handlers.call_method = zend_test_class_call_method; +#endif + return SUCCESS; } /* }}} */ @@ -425,12 +491,16 @@ ZEND_FUNCTION(func_num_args) { zend_execute_data *ex = EX(prev_execute_data); - if (!(ZEND_CALL_INFO(ex) & ZEND_CALL_CODE)) { - RETURN_LONG(ZEND_CALL_NUM_ARGS(ex)); - } else { + if (ZEND_CALL_INFO(ex) & ZEND_CALL_CODE) { zend_error(E_WARNING, "func_num_args(): Called from the global scope - no function context"); RETURN_LONG(-1); } + + if (zend_forbid_dynamic_call("func_num_args()") == FAILURE) { + RETURN_LONG(-1); + } + + RETURN_LONG(ZEND_CALL_NUM_ARGS(ex)); } /* }}} */ @@ -458,15 +528,19 @@ ZEND_FUNCTION(func_get_arg) RETURN_FALSE; } + if (zend_forbid_dynamic_call("func_get_arg()") == FAILURE) { + RETURN_FALSE; + } + arg_count = ZEND_CALL_NUM_ARGS(ex); - if (requested_offset >= arg_count) { + if ((zend_ulong)requested_offset >= arg_count) { zend_error(E_WARNING, "func_get_arg(): Argument " ZEND_LONG_FMT " not passed to function", requested_offset); RETURN_FALSE; } first_extra_arg = ex->func->op_array.num_args; - if (requested_offset >= first_extra_arg && (ZEND_CALL_NUM_ARGS(ex) > first_extra_arg)) { + if ((zend_ulong)requested_offset >= first_extra_arg && (ZEND_CALL_NUM_ARGS(ex) > first_extra_arg)) { arg = ZEND_CALL_VAR_NUM(ex, ex->func->op_array.last_var + ex->func->op_array.T) + (requested_offset - first_extra_arg); } else { arg = ZEND_CALL_ARG(ex, requested_offset + 1); @@ -492,6 +566,10 @@ ZEND_FUNCTION(func_get_args) RETURN_FALSE; } + if (zend_forbid_dynamic_call("func_get_args()") == FAILURE) { + RETURN_FALSE; + } + arg_count = ZEND_CALL_NUM_ARGS(ex); array_init_size(return_value, arg_count); @@ -670,7 +748,7 @@ ZEND_FUNCTION(each) if (Z_REFCOUNTED_P(entry)) Z_ADDREF_P(entry); } zend_hash_index_add_new(Z_ARRVAL_P(return_value), 1, entry); - zend_hash_str_add_new(Z_ARRVAL_P(return_value), "value", sizeof("value")-1, entry); + zend_hash_add_new(Z_ARRVAL_P(return_value), CG(known_strings)[ZEND_STR_VALUE], entry); /* add the key elements */ if (zend_hash_get_current_key(target_hash, &key, &num_key) == HASH_KEY_IS_STRING) { @@ -680,7 +758,7 @@ ZEND_FUNCTION(each) ZVAL_LONG(&tmp, num_key); } zend_hash_index_add_new(Z_ARRVAL_P(return_value), 0, &tmp); - zend_hash_str_add_new(Z_ARRVAL_P(return_value), "key", sizeof("key")-1, &tmp); + zend_hash_add_new(Z_ARRVAL_P(return_value), CG(known_strings)[ZEND_STR_KEY], &tmp); zend_hash_move_forward(target_hash); } /* }}} */ @@ -689,7 +767,7 @@ ZEND_FUNCTION(each) Return the current error_reporting level, and if an argument was passed - change to the new level */ ZEND_FUNCTION(error_reporting) { - zval *err; + zval *err = NULL; int old_error_reporting; #ifndef FAST_ZPP @@ -710,7 +788,7 @@ ZEND_FUNCTION(error_reporting) zend_ini_entry *p = EG(error_reporting_ini_entry); if (!p) { - p = zend_hash_str_find_ptr(EG(ini_directives), "error_reporting", sizeof("error_reporting")-1); + p = zend_hash_find_ptr(EG(ini_directives), CG(known_strings)[ZEND_STR_ERROR_REPORTING]); if (p) { EG(error_reporting_ini_entry) = p; } else { @@ -722,7 +800,7 @@ ZEND_FUNCTION(error_reporting) ALLOC_HASHTABLE(EG(modified_ini_directives)); zend_hash_init(EG(modified_ini_directives), 8, NULL, NULL, 0); } - if (EXPECTED(zend_hash_str_add_ptr(EG(modified_ini_directives), "error_reporting", sizeof("error_reporting")-1, p) != NULL)) { + if (EXPECTED(zend_hash_add_ptr(EG(modified_ini_directives), CG(known_strings)[ZEND_STR_ERROR_REPORTING], p) != NULL)) { p->orig_value = p->value; p->orig_modifiable = p->modifiable; p->modified = 1; @@ -917,7 +995,7 @@ ZEND_FUNCTION(defined) ZEND_PARSE_PARAMETERS_END(); #endif - if (zend_get_constant_ex(name, NULL, ZEND_FETCH_CLASS_SILENT)) { + if (zend_get_constant_ex(name, zend_get_executed_scope(), ZEND_FETCH_CLASS_SILENT)) { RETURN_TRUE; } else { RETURN_FALSE; @@ -936,8 +1014,10 @@ ZEND_FUNCTION(get_class) } if (!obj) { - if (EG(scope)) { - RETURN_STR_COPY(EG(scope)->name); + zend_class_entry *scope = zend_get_executed_scope(); + + if (scope) { + RETURN_STR_COPY(scope->name); } else { zend_error(E_WARNING, "get_class() called without object from outside a class"); RETURN_FALSE; @@ -961,8 +1041,11 @@ ZEND_FUNCTION(get_called_class) called_scope = zend_get_called_scope(execute_data); if (called_scope) { RETURN_STR_COPY(called_scope->name); - } else if (!EG(scope)) { - zend_error(E_WARNING, "get_called_class() called from outside a class"); + } else { + zend_class_entry *scope = zend_get_executed_scope(); + if (!scope) { + zend_error(E_WARNING, "get_called_class() called from outside a class"); + } } RETURN_FALSE; } @@ -980,7 +1063,7 @@ ZEND_FUNCTION(get_parent_class) } if (!ZEND_NUM_ARGS()) { - ce = EG(scope); + ce = zend_get_executed_scope(); if (ce && ce->parent) { RETURN_STR_COPY(ce->parent->name); } else { @@ -1077,7 +1160,7 @@ ZEND_FUNCTION(is_a) /* }}} */ /* {{{ add_class_vars */ -static void add_class_vars(zend_class_entry *ce, int statics, zval *return_value) +static void add_class_vars(zend_class_entry *scope, zend_class_entry *ce, int statics, zval *return_value) { zend_property_info *prop_info; zval *prop, prop_copy; @@ -1085,12 +1168,12 @@ static void add_class_vars(zend_class_entry *ce, int statics, zval *return_value ZEND_HASH_FOREACH_STR_KEY_PTR(&ce->properties_info, key, prop_info) { if (((prop_info->flags & ZEND_ACC_SHADOW) && - prop_info->ce != EG(scope)) || + prop_info->ce != scope) || ((prop_info->flags & ZEND_ACC_PROTECTED) && - !zend_check_protected(prop_info->ce, EG(scope))) || + !zend_check_protected(prop_info->ce, scope)) || ((prop_info->flags & ZEND_ACC_PRIVATE) && - ce != EG(scope) && - prop_info->ce != EG(scope))) { + ce != scope && + prop_info->ce != scope)) { continue; } prop = NULL; @@ -1115,7 +1198,7 @@ static void add_class_vars(zend_class_entry *ce, int statics, zval *return_value /* this is necessary to make it able to work with default array * properties, returned to user */ if (Z_OPT_CONSTANT_P(prop)) { - if (UNEXPECTED(zval_update_constant_ex(prop, 0, NULL) != SUCCESS)) { + if (UNEXPECTED(zval_update_constant_ex(prop, NULL) != SUCCESS)) { return; } } @@ -1130,7 +1213,7 @@ static void add_class_vars(zend_class_entry *ce, int statics, zval *return_value ZEND_FUNCTION(get_class_vars) { zend_string *class_name; - zend_class_entry *ce; + zend_class_entry *ce, *scope; if (zend_parse_parameters(ZEND_NUM_ARGS(), "S", &class_name) == FAILURE) { return; @@ -1146,8 +1229,9 @@ ZEND_FUNCTION(get_class_vars) return; } } - add_class_vars(ce, 0, return_value); - add_class_vars(ce, 1, return_value); + scope = zend_get_executed_scope(); + add_class_vars(scope, ce, 0, return_value); + add_class_vars(scope, ce, 1, return_value); } } /* }}} */ @@ -1245,6 +1329,7 @@ ZEND_FUNCTION(get_class_methods) zval *klass; zval method_name; zend_class_entry *ce = NULL; + zend_class_entry *scope; zend_function *mptr; zend_string *key; @@ -1263,15 +1348,16 @@ ZEND_FUNCTION(get_class_methods) } array_init(return_value); + scope = zend_get_executed_scope(); ZEND_HASH_FOREACH_STR_KEY_PTR(&ce->function_table, key, mptr) { if ((mptr->common.fn_flags & ZEND_ACC_PUBLIC) - || (EG(scope) && + || (scope && (((mptr->common.fn_flags & ZEND_ACC_PROTECTED) && - zend_check_protected(mptr->common.scope, EG(scope))) + zend_check_protected(mptr->common.scope, scope)) || ((mptr->common.fn_flags & ZEND_ACC_PRIVATE) && - EG(scope) == mptr->common.scope)))) { + scope == mptr->common.scope)))) { size_t len = ZSTR_LEN(mptr->common.function_name); /* Do not display old-style inherited constructors */ @@ -1950,8 +2036,12 @@ ZEND_FUNCTION(get_defined_functions) Returns an associative array of names and values of all currently defined variable names (variables in the current scope) */ ZEND_FUNCTION(get_defined_vars) { - zend_array *symbol_table = zend_rebuild_symbol_table(); + zend_array *symbol_table; + if (zend_forbid_dynamic_call("get_defined_vars()") == FAILURE) { + return; + } + symbol_table = zend_rebuild_symbol_table(); if (UNEXPECTED(symbol_table == NULL)) { return; } @@ -2037,17 +2127,16 @@ ZEND_FUNCTION(zend_test_func) { zval *arg1, *arg2; - zend_get_parameters(ZEND_NUM_ARGS(), 2, &arg1, &arg2); + zend_parse_parameters(ZEND_NUM_ARGS(), "|zz", &arg1, &arg2); } ZEND_FUNCTION(zend_test_func2) { zval *arg1, *arg2; - zend_get_parameters(ZEND_NUM_ARGS(), 2, &arg1, &arg2); + zend_parse_parameters(ZEND_NUM_ARGS(), "|zz", &arg1, &arg2); } - #ifdef ZTS ZEND_FUNCTION(zend_thread_id) { @@ -2369,7 +2458,7 @@ ZEND_FUNCTION(debug_print_backtrace) } /* $this may be passed into regular internal functions */ - object = Z_OBJ(call->This); + object = (Z_TYPE(call->This) == IS_OBJECT) ? Z_OBJ(call->This) : NULL; if (call->func) { func = call->func; @@ -2504,7 +2593,7 @@ ZEND_API void zend_fetch_debug_backtrace(zval *return_value, int skip_last, int zend_string *function_name; zend_string *filename; zend_string *include_filename = NULL; - zval stack_frame; + zval stack_frame, tmp; array_init(return_value); @@ -2566,8 +2655,10 @@ ZEND_API void zend_fetch_debug_backtrace(zval *return_value, int skip_last, int } else { lineno = skip->opline->lineno; } - add_assoc_str_ex(&stack_frame, "file", sizeof("file")-1, zend_string_copy(filename)); - add_assoc_long_ex(&stack_frame, "line", sizeof("line")-1, lineno); + ZVAL_STR_COPY(&tmp, filename); + zend_hash_add_new(Z_ARRVAL(stack_frame), CG(known_strings)[ZEND_STR_FILE], &tmp); + ZVAL_LONG(&tmp, lineno); + zend_hash_add_new(Z_ARRVAL(stack_frame), CG(known_strings)[ZEND_STR_LINE], &tmp); /* try to fetch args only if an FCALL was just made - elsewise we're in the middle of a function * and debug_baktrace() might have been called by the error_handler. in this case we don't @@ -2584,8 +2675,10 @@ ZEND_API void zend_fetch_debug_backtrace(zval *return_value, int skip_last, int break; } if (prev->func && ZEND_USER_CODE(prev->func->common.type)) { - add_assoc_str_ex(&stack_frame, "file", sizeof("file")-1, zend_string_copy(prev->func->op_array.filename)); - add_assoc_long_ex(&stack_frame, "line", sizeof("line")-1, prev->opline->lineno); + ZVAL_STR_COPY(&tmp, prev->func->op_array.filename); + zend_hash_add_new(Z_ARRVAL(stack_frame), CG(known_strings)[ZEND_STR_FILE], &tmp); + ZVAL_LONG(&tmp, prev->opline->lineno); + zend_hash_add_new(Z_ARRVAL(stack_frame), CG(known_strings)[ZEND_STR_LINE], &tmp); break; } prev_call = prev; @@ -2595,7 +2688,7 @@ ZEND_API void zend_fetch_debug_backtrace(zval *return_value, int skip_last, int } /* $this may be passed into regular internal functions */ - object = call ? Z_OBJ(call->This) : NULL; + object = (call && (Z_TYPE(call->This) == IS_OBJECT)) ? Z_OBJ(call->This) : NULL; if (call && call->func) { func = call->func; @@ -2610,68 +2703,70 @@ ZEND_API void zend_fetch_debug_backtrace(zval *return_value, int skip_last, int } if (function_name) { - add_assoc_str_ex(&stack_frame, "function", sizeof("function")-1, zend_string_copy(function_name)); + ZVAL_STR_COPY(&tmp, function_name); + zend_hash_add_new(Z_ARRVAL(stack_frame), CG(known_strings)[ZEND_STR_FUNCTION], &tmp); if (object) { if (func->common.scope) { - add_assoc_str_ex(&stack_frame, "class", sizeof("class")-1, zend_string_copy(func->common.scope->name)); + ZVAL_STR_COPY(&tmp, func->common.scope->name); } else if (object->handlers->get_class_name == std_object_handlers.get_class_name) { - add_assoc_str_ex(&stack_frame, "class", sizeof("class")-1, zend_string_copy(object->ce->name)); + ZVAL_STR_COPY(&tmp, object->ce->name); } else { - zend_string *class_name = object->handlers->get_class_name(object); - add_assoc_str_ex(&stack_frame, "class", sizeof("class")-1, class_name); + ZVAL_STR(&tmp, object->handlers->get_class_name(object)); } + zend_hash_add_new(Z_ARRVAL(stack_frame), CG(known_strings)[ZEND_STR_CLASS], &tmp); if ((options & DEBUG_BACKTRACE_PROVIDE_OBJECT) != 0) { - zval zv; - ZVAL_OBJ(&zv, object); - add_assoc_zval_ex(&stack_frame, "object", sizeof("object")-1, &zv); - Z_ADDREF(zv); + ZVAL_OBJ(&tmp, object); + zend_hash_add_new(Z_ARRVAL(stack_frame), CG(known_strings)[ZEND_STR_OBJECT], &tmp); + Z_ADDREF(tmp); } - add_assoc_string_ex(&stack_frame, "type", sizeof("type")-1, "->"); + ZVAL_INTERNED_STR(&tmp, CG(known_strings)[ZEND_STR_OBJECT_OPERATOR]); + zend_hash_add_new(Z_ARRVAL(stack_frame), CG(known_strings)[ZEND_STR_TYPE], &tmp); } else if (func->common.scope) { - add_assoc_str_ex(&stack_frame, "class", sizeof("class")-1, zend_string_copy(func->common.scope->name)); - add_assoc_string_ex(&stack_frame, "type", sizeof("type")-1, "::"); + ZVAL_STR_COPY(&tmp, func->common.scope->name); + zend_hash_add_new(Z_ARRVAL(stack_frame), CG(known_strings)[ZEND_STR_CLASS], &tmp); + ZVAL_INTERNED_STR(&tmp, CG(known_strings)[ZEND_STR_PAAMAYIM_NEKUDOTAYIM]); + zend_hash_add_new(Z_ARRVAL(stack_frame), CG(known_strings)[ZEND_STR_TYPE], &tmp); } if ((options & DEBUG_BACKTRACE_IGNORE_ARGS) == 0 && func->type != ZEND_EVAL_CODE) { - zval args; - debug_backtrace_get_args(call, &args); - add_assoc_zval_ex(&stack_frame, "args", sizeof("args")-1, &args); + debug_backtrace_get_args(call, &tmp); + zend_hash_add_new(Z_ARRVAL(stack_frame), CG(known_strings)[ZEND_STR_ARGS], &tmp); } } else { /* i know this is kinda ugly, but i'm trying to avoid extra cycles in the main execution loop */ zend_bool build_filename_arg = 1; - const char *pseudo_function_name; + zend_string *pseudo_function_name; if (!ptr->func || !ZEND_USER_CODE(ptr->func->common.type) || ptr->opline->opcode != ZEND_INCLUDE_OR_EVAL) { /* can happen when calling eval from a custom sapi */ - pseudo_function_name = "unknown"; + pseudo_function_name = CG(known_strings)[ZEND_STR_UNKNOWN]; build_filename_arg = 0; } else switch (ptr->opline->extended_value) { case ZEND_EVAL: - pseudo_function_name = "eval"; + pseudo_function_name = CG(known_strings)[ZEND_STR_EVAL]; build_filename_arg = 0; break; case ZEND_INCLUDE: - pseudo_function_name = "include"; + pseudo_function_name = CG(known_strings)[ZEND_STR_INCLUDE]; break; case ZEND_REQUIRE: - pseudo_function_name = "require"; + pseudo_function_name = CG(known_strings)[ZEND_STR_REQUIRE]; break; case ZEND_INCLUDE_ONCE: - pseudo_function_name = "include_once"; + pseudo_function_name = CG(known_strings)[ZEND_STR_INCLUDE_ONCE]; break; case ZEND_REQUIRE_ONCE: - pseudo_function_name = "require_once"; + pseudo_function_name = CG(known_strings)[ZEND_STR_REQUIRE_ONCE]; break; default: /* this can actually happen if you use debug_backtrace() in your error_handler and * you're in the top-scope */ - pseudo_function_name = "unknown"; + pseudo_function_name = CG(known_strings)[ZEND_STR_UNKNOWN]; build_filename_arg = 0; break; } @@ -2685,11 +2780,13 @@ ZEND_API void zend_fetch_debug_backtrace(zval *return_value, int skip_last, int if we have called include in the frame above - this is the file we have included. */ - add_next_index_str(&arg_array, zend_string_copy(include_filename)); - add_assoc_zval_ex(&stack_frame, "args", sizeof("args")-1, &arg_array); + ZVAL_STR_COPY(&tmp, include_filename); + zend_hash_next_index_insert_new(Z_ARRVAL(arg_array), &tmp); + zend_hash_add_new(Z_ARRVAL(stack_frame), CG(known_strings)[ZEND_STR_ARGS], &arg_array); } - add_assoc_string_ex(&stack_frame, "function", sizeof("function")-1, (char *) pseudo_function_name); + ZVAL_INTERNED_STR(&tmp, pseudo_function_name); + zend_hash_add_new(Z_ARRVAL(stack_frame), CG(known_strings)[ZEND_STR_FUNCTION], &tmp); } zend_hash_next_index_insert_new(Z_ARRVAL_P(return_value), &stack_frame); |