diff options
Diffstat (limited to 'Zend/zend_builtin_functions.c')
-rw-r--r-- | Zend/zend_builtin_functions.c | 158 |
1 files changed, 96 insertions, 62 deletions
diff --git a/Zend/zend_builtin_functions.c b/Zend/zend_builtin_functions.c index 0b48df48bf..5ae536f425 100644 --- a/Zend/zend_builtin_functions.c +++ b/Zend/zend_builtin_functions.c @@ -491,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)); } /* }}} */ @@ -524,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); @@ -558,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); @@ -736,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) { @@ -746,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); } /* }}} */ @@ -770,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 { @@ -787,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; @@ -796,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 { @@ -982,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; @@ -1001,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; @@ -1026,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; } @@ -1045,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 { @@ -1142,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; @@ -1150,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; @@ -1180,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; } } @@ -1195,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; @@ -1211,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); } } /* }}} */ @@ -1249,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))) { @@ -1310,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; @@ -1328,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 */ @@ -2015,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; } @@ -2433,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; @@ -2561,7 +2586,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); @@ -2623,8 +2648,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 @@ -2641,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; @@ -2652,7 +2681,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; @@ -2667,66 +2696,69 @@ 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 { - 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; - 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; } @@ -2740,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_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); |