summaryrefslogtreecommitdiff
path: root/Zend/zend_builtin_functions.c
diff options
context:
space:
mode:
Diffstat (limited to 'Zend/zend_builtin_functions.c')
-rw-r--r--Zend/zend_builtin_functions.c347
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);