diff options
Diffstat (limited to 'Zend/zend_builtin_functions.c')
-rw-r--r-- | Zend/zend_builtin_functions.c | 347 |
1 files changed, 250 insertions, 97 deletions
diff --git a/Zend/zend_builtin_functions.c b/Zend/zend_builtin_functions.c index 1a5ba2e5dd..5ae536f425 100644 --- a/Zend/zend_builtin_functions.c +++ b/Zend/zend_builtin_functions.c @@ -2,7 +2,7 @@ +----------------------------------------------------------------------+ | Zend Engine | +----------------------------------------------------------------------+ - | Copyright (c) 1998-2015 Zend Technologies Ltd. (http://www.zend.com) | + | Copyright (c) 1998-2016 Zend Technologies Ltd. (http://www.zend.com) | +----------------------------------------------------------------------+ | This source file is subject to version 2.00 of the Zend license, | | that is bundled with this package in the file LICENSE, and is | @@ -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); @@ -93,6 +99,7 @@ static ZEND_FUNCTION(zend_test_func2); static ZEND_FUNCTION(zend_thread_id); #endif #endif +static ZEND_FUNCTION(gc_mem_caches); static ZEND_FUNCTION(gc_collect_cycles); static ZEND_FUNCTION(gc_enabled); static ZEND_FUNCTION(gc_enable); @@ -247,7 +254,7 @@ ZEND_BEGIN_ARG_INFO_EX(arginfo_extension_loaded, 0, 0, 1) ZEND_ARG_INFO(0, extension_name) ZEND_END_ARG_INFO() -#ifdef ZEND_DEBUG +#if ZEND_DEBUG ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO(arginfo_zend_test_func, IS_ARRAY, NULL, 0) ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO(arginfo_zend_test_func2, IS_ARRAY, NULL, 1) @@ -256,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) @@ -321,6 +373,7 @@ static const zend_function_entry builtin_functions[] = { /* {{{ */ ZEND_FE(zend_thread_id, NULL) #endif #endif + ZEND_FE(gc_mem_caches, arginfo_zend__void) ZEND_FE(gc_collect_cycles, arginfo_zend__void) ZEND_FE(gc_enabled, arginfo_zend__void) ZEND_FE(gc_enable, arginfo_zend__void) @@ -337,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; } /* }}} */ @@ -371,6 +439,15 @@ ZEND_FUNCTION(zend_version) } /* }}} */ +/* {{{ proto int gc_mem_caches(void) + Reclaims memory used by MM caches. + Returns number of freed bytes */ +ZEND_FUNCTION(gc_mem_caches) +{ + RETURN_LONG(zend_mm_gc(zend_mm_get_heap())); +} +/* }}} */ + /* {{{ proto int gc_collect_cycles(void) Forces collection of any existing garbage cycles. Returns number of freed zvals */ @@ -414,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)); } /* }}} */ @@ -447,21 +528,27 @@ 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); } - ZVAL_DEREF(arg); - ZVAL_COPY(return_value, arg); + if (EXPECTED(!Z_ISUNDEF_P(arg))) { + ZVAL_DEREF(arg); + ZVAL_COPY(return_value, arg); + } } /* }}} */ @@ -471,7 +558,7 @@ ZEND_FUNCTION(func_get_args) { zval *p, *q; uint32_t arg_count, first_extra_arg; - uint32_t i; + uint32_t i, n; zend_execute_data *ex = EX(prev_execute_data); if (ZEND_CALL_INFO(ex) & ZEND_CALL_CODE) { @@ -479,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); @@ -487,12 +578,18 @@ ZEND_FUNCTION(func_get_args) zend_hash_real_init(Z_ARRVAL_P(return_value), 1); ZEND_HASH_FILL_PACKED(Z_ARRVAL_P(return_value)) { i = 0; + n = 0; p = ZEND_CALL_ARG(ex, 1); if (arg_count > first_extra_arg) { while (i < first_extra_arg) { q = p; - ZVAL_DEREF(q); - if (Z_OPT_REFCOUNTED_P(q)) Z_ADDREF_P(q); + if (EXPECTED(Z_TYPE_INFO_P(q) != IS_UNDEF)) { + ZVAL_DEREF(q); + if (Z_OPT_REFCOUNTED_P(q)) { + Z_ADDREF_P(q); + } + n++; + } ZEND_HASH_FILL_ADD(q); p++; i++; @@ -501,13 +598,19 @@ ZEND_FUNCTION(func_get_args) } while (i < arg_count) { q = p; - ZVAL_DEREF(q); - if (Z_OPT_REFCOUNTED_P(q)) Z_ADDREF_P(q); + if (EXPECTED(Z_TYPE_INFO_P(q) != IS_UNDEF)) { + ZVAL_DEREF(q); + if (Z_OPT_REFCOUNTED_P(q)) { + Z_ADDREF_P(q); + } + n++; + } ZEND_HASH_FILL_ADD(q); p++; i++; } } ZEND_HASH_FILL_END(); + Z_ARRVAL_P(return_value)->nNumOfElements = n; } } /* }}} */ @@ -645,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) { @@ -655,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); } /* }}} */ @@ -679,12 +782,13 @@ ZEND_FUNCTION(error_reporting) #endif old_error_reporting = EG(error_reporting); - if(ZEND_NUM_ARGS() != 0) { + if (ZEND_NUM_ARGS() != 0) { + zend_string *new_val = zval_get_string(err); do { 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 { @@ -696,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; @@ -705,7 +809,7 @@ ZEND_FUNCTION(error_reporting) zend_string_release(p->value); } - p->value = zval_get_string(err); + p->value = new_val; if (Z_TYPE_P(err) == IS_LONG) { EG(error_reporting) = Z_LVAL_P(err); } else { @@ -771,6 +875,9 @@ static void copy_constant_array(zval *dst, zval *src) /* {{{ */ } } else if (Z_REFCOUNTED_P(val)) { Z_ADDREF_P(val); + if (UNEXPECTED(Z_TYPE_INFO_P(val) == IS_RESOURCE_EX)) { + Z_TYPE_INFO_P(new_val) &= ~(IS_TYPE_REFCOUNTED << Z_TYPE_FLAGS_SHIFT); + } } } ZEND_HASH_FOREACH_END(); } @@ -799,7 +906,7 @@ ZEND_FUNCTION(define) ZEND_PARSE_PARAMETERS_END(); #endif - if(non_cs) { + if (non_cs) { case_sensitive = 0; } @@ -818,9 +925,14 @@ repeat: case IS_STRING: case IS_FALSE: case IS_TRUE: - case IS_RESOURCE: case IS_NULL: break; + case IS_RESOURCE: + ZVAL_COPY(&val_free, val); + /* TODO: better solution than this tricky disable dtor on resource? */ + Z_TYPE_INFO(val_free) &= ~(IS_TYPE_REFCOUNTED << Z_TYPE_FLAGS_SHIFT); + val = &val_free; + break; case IS_ARRAY: if (!Z_IMMUTABLE_P(val)) { if (!validate_constant_array(Z_ARRVAL_P(val))) { @@ -883,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; @@ -902,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; @@ -927,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; } @@ -946,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 { @@ -1043,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; @@ -1051,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; @@ -1081,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; } } @@ -1096,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; @@ -1112,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); } } /* }}} */ @@ -1150,7 +1268,7 @@ ZEND_FUNCTION(get_object_vars) zobj = Z_OBJ_P(obj); - if (!zobj->ce->default_properties_count && properties == zobj->properties) { + if (!zobj->ce->default_properties_count && properties == zobj->properties && !ZEND_HASH_GET_APPLY_COUNT(properties)) { /* fast copy */ if (EXPECTED(zobj->handlers == &std_object_handlers)) { if (EXPECTED(!(GC_FLAGS(properties) & IS_ARRAY_IMMUTABLE))) { @@ -1165,8 +1283,12 @@ ZEND_FUNCTION(get_object_vars) ZEND_HASH_FOREACH_STR_KEY_VAL_IND(properties, key, value) { if (key) { if (zend_check_property_access(zobj, key) == SUCCESS) { - /* Not separating references */ - if (Z_REFCOUNTED_P(value)) Z_ADDREF_P(value); + if (Z_ISREF_P(value) && Z_REFCOUNT_P(value) == 1) { + value = Z_REFVAL_P(value); + } + if (Z_REFCOUNTED_P(value)) { + Z_ADDREF_P(value); + } if (ZSTR_VAL(key)[0] == 0) { const char *prop_name, *class_name; size_t prop_len; @@ -1207,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; @@ -1225,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 */ @@ -1912,7 +2036,15 @@ 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; + } RETURN_ARR(zend_array_dup(symbol_table)); } @@ -1995,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) { @@ -2205,6 +2336,7 @@ static void debug_backtrace_get_args(zend_execute_data *call, zval *arg_array) / array_init_size(arg_array, num_args); if (num_args) { uint32_t i = 0; + uint32_t n = 0; zval *p = ZEND_CALL_ARG(call, 1); zend_hash_real_init(Z_ARRVAL_P(arg_array), 1); @@ -2214,9 +2346,13 @@ static void debug_backtrace_get_args(zend_execute_data *call, zval *arg_array) / if (ZEND_CALL_NUM_ARGS(call) > first_extra_arg) { while (i < first_extra_arg) { - if (Z_OPT_REFCOUNTED_P(p)) Z_ADDREF_P(p); + if (EXPECTED(Z_TYPE_INFO_P(p) != IS_UNDEF)) { + if (Z_OPT_REFCOUNTED_P(p)) { + Z_ADDREF_P(p); + } + n++; + } ZEND_HASH_FILL_ADD(p); - zend_hash_next_index_insert_new(Z_ARRVAL_P(arg_array), p); p++; i++; } @@ -2225,12 +2361,18 @@ static void debug_backtrace_get_args(zend_execute_data *call, zval *arg_array) / } while (i < num_args) { - if (Z_OPT_REFCOUNTED_P(p)) Z_ADDREF_P(p); + if (EXPECTED(Z_TYPE_INFO_P(p) != IS_UNDEF)) { + if (Z_OPT_REFCOUNTED_P(p)) { + Z_ADDREF_P(p); + } + n++; + } ZEND_HASH_FILL_ADD(p); p++; i++; } } ZEND_HASH_FILL_END(); + Z_ARRVAL_P(arg_array)->nNumOfElements = n; } } /* }}} */ @@ -2316,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; @@ -2437,17 +2579,21 @@ ZEND_FUNCTION(debug_print_backtrace) ZEND_API void zend_fetch_debug_backtrace(zval *return_value, int skip_last, int options, int limit) /* {{{ */ { - zend_execute_data *call, *ptr, *skip; + zend_execute_data *ptr, *skip, *call = NULL; zend_object *object; int lineno, frameno = 0; zend_function *func; - const char *function_name; - const char *filename; - const char *include_filename = NULL; - zval stack_frame; + zend_string *function_name; + zend_string *filename; + zend_string *include_filename = NULL; + zval stack_frame, tmp; + + array_init(return_value); + + if (!(ptr = EG(current_execute_data))) { + return; + } - call = NULL; - ptr = EG(current_execute_data); if (!ptr->func || !ZEND_USER_CODE(ptr->func->common.type)) { call = ptr; ptr = ptr->prev_execute_data; @@ -2465,13 +2611,11 @@ ZEND_API void zend_fetch_debug_backtrace(zval *return_value, int skip_last, int ptr = ptr->prev_execute_data; } } + if (!call) { + call = ptr; + ptr = ptr->prev_execute_data; + } } - if (!call) { - call = ptr; - ptr = ptr->prev_execute_data; - } - - array_init(return_value); while (ptr && (limit == 0 || frameno < limit)) { frameno++; @@ -2494,7 +2638,7 @@ ZEND_API void zend_fetch_debug_backtrace(zval *return_value, int skip_last, int } if (skip->func && ZEND_USER_CODE(skip->func->common.type)) { - filename = ZSTR_VAL(skip->func->op_array.filename); + filename = skip->func->op_array.filename; if (skip->opline->opcode == ZEND_HANDLE_EXCEPTION) { if (EG(opline_before_exception)) { lineno = EG(opline_before_exception)->lineno; @@ -2504,8 +2648,10 @@ ZEND_API void zend_fetch_debug_backtrace(zval *return_value, int skip_last, int } else { lineno = skip->opline->lineno; } - add_assoc_string_ex(&stack_frame, "file", sizeof("file")-1, (char*)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 @@ -2522,8 +2668,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; @@ -2533,81 +2681,84 @@ 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; function_name = (func->common.scope && func->common.scope->trait_aliases) ? - ZSTR_VAL(zend_resolve_method_name( - (object ? object->ce : func->common.scope), func)) : - (func->common.function_name ? - ZSTR_VAL(func->common.function_name) : NULL); + zend_resolve_method_name( + (object ? object->ce : func->common.scope), func) : + func->common.function_name; } else { func = NULL; function_name = NULL; } if (function_name) { - add_assoc_string_ex(&stack_frame, "function", sizeof("function")-1, (char*)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 { - add_assoc_str_ex(&stack_frame, "class", sizeof("class")-1, zend_string_copy(object->ce->name)); + ZVAL_STR_COPY(&tmp, object->ce->name); } + 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; + 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 */ - 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: - function_name = "eval"; + pseudo_function_name = CG(known_strings)[ZEND_STR_EVAL]; build_filename_arg = 0; break; case ZEND_INCLUDE: - function_name = "include"; + pseudo_function_name = CG(known_strings)[ZEND_STR_INCLUDE]; break; case ZEND_REQUIRE: - function_name = "require"; + pseudo_function_name = CG(known_strings)[ZEND_STR_REQUIRE]; break; case ZEND_INCLUDE_ONCE: - function_name = "include_once"; + pseudo_function_name = CG(known_strings)[ZEND_STR_INCLUDE_ONCE]; break; case ZEND_REQUIRE_ONCE: - 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 */ - function_name = "unknown"; + pseudo_function_name = CG(known_strings)[ZEND_STR_UNKNOWN]; build_filename_arg = 0; break; } @@ -2621,11 +2772,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_string(&arg_array, (char*)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*)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); |