diff options
Diffstat (limited to 'Zend/zend_execute_API.c')
-rw-r--r-- | Zend/zend_execute_API.c | 255 |
1 files changed, 96 insertions, 159 deletions
diff --git a/Zend/zend_execute_API.c b/Zend/zend_execute_API.c index 9f10843b6b..a551449e79 100644 --- a/Zend/zend_execute_API.c +++ b/Zend/zend_execute_API.c @@ -12,14 +12,12 @@ | obtain it through the world-wide-web, please send a note to | | license@zend.com so we can mail you a copy immediately. | +----------------------------------------------------------------------+ - | Authors: Andi Gutmans <andi@zend.com> | - | Zeev Suraski <zeev@zend.com> | - | Dmitry Stogov <dmitry@zend.com> | + | Authors: Andi Gutmans <andi@php.net> | + | Zeev Suraski <zeev@php.net> | + | Dmitry Stogov <dmitry@php.net> | +----------------------------------------------------------------------+ */ -/* $Id$ */ - #include <stdio.h> #include <signal.h> @@ -47,7 +45,7 @@ ZEND_API void (*zend_execute_internal)(zend_execute_data *execute_data, zval *re /* true globals */ ZEND_API const zend_fcall_info empty_fcall_info = { 0, {{0}, {{0}}, {0}}, NULL, NULL, NULL, 0, 0 }; -ZEND_API const zend_fcall_info_cache empty_fcall_info_cache = { 0, NULL, NULL, NULL, NULL }; +ZEND_API const zend_fcall_info_cache empty_fcall_info_cache = { NULL, NULL, NULL, NULL }; #ifdef ZEND_WIN32 ZEND_TLS HANDLE tq_timer = NULL; @@ -103,7 +101,7 @@ static void zend_extension_deactivator(zend_extension *extension) /* {{{ */ static int clean_non_persistent_constant_full(zval *zv) /* {{{ */ { zend_constant *c = Z_PTR_P(zv); - return (c->flags & CONST_PERSISTENT) ? ZEND_HASH_APPLY_KEEP : ZEND_HASH_APPLY_REMOVE; + return (ZEND_CONSTANT_FLAGS(c) & CONST_PERSISTENT) ? ZEND_HASH_APPLY_KEEP : ZEND_HASH_APPLY_REMOVE; } /* }}} */ @@ -181,6 +179,10 @@ void init_executor(void) /* {{{ */ EG(each_deprecation_thrown) = 0; + EG(persistent_constants_count) = EG(zend_constants)->nNumUsed; + EG(persistent_functions_count) = EG(function_table)->nNumUsed; + EG(persistent_classes_count) = EG(class_table)->nNumUsed; + EG(active) = 1; } /* }}} */ @@ -279,31 +281,15 @@ void shutdown_executor(void) /* {{{ */ * Zend Memory Manager frees memory by its own. We don't have to free * each allocated block separately. */ - ZEND_HASH_REVERSE_FOREACH_VAL(EG(zend_constants), zv) { - zend_constant *c = Z_PTR_P(zv); - if (c->flags & CONST_PERSISTENT) { - break; - } - } ZEND_HASH_FOREACH_END_DEL(); - ZEND_HASH_REVERSE_FOREACH_VAL(EG(function_table), zv) { - zend_function *func = Z_PTR_P(zv); - if (func->type == ZEND_INTERNAL_FUNCTION) { - break; - } - } ZEND_HASH_FOREACH_END_DEL(); - ZEND_HASH_REVERSE_FOREACH_VAL(EG(class_table), zv) { - zend_class_entry *ce = Z_PTR_P(zv); - if (ce->type == ZEND_INTERNAL_CLASS) { - break; - } - } ZEND_HASH_FOREACH_END_DEL(); - + zend_hash_discard(EG(zend_constants), EG(persistent_constants_count)); + zend_hash_discard(EG(function_table), EG(persistent_functions_count)); + zend_hash_discard(EG(class_table), EG(persistent_classes_count)); zend_cleanup_internal_classes(); } else { zend_hash_graceful_reverse_destroy(&EG(symbol_table)); #if ZEND_DEBUG - if (GC_G(gc_enabled) && !CG(unclean_shutdown)) { + if (gc_enabled() && !CG(unclean_shutdown)) { gc_collect_cycles(); } #endif @@ -333,15 +319,15 @@ void shutdown_executor(void) /* {{{ */ } else { ZEND_HASH_REVERSE_FOREACH_STR_KEY_VAL(EG(zend_constants), key, zv) { zend_constant *c = Z_PTR_P(zv); - if (c->flags & CONST_PERSISTENT) { + if (ZEND_CONSTANT_FLAGS(c) & CONST_PERSISTENT) { break; } - zval_ptr_dtor(&c->value); + zval_ptr_dtor_nogc(&c->value); if (c->name) { - zend_string_release(c->name); + zend_string_release_ex(c->name, 0); } efree(c); - zend_string_release(key); + zend_string_release_ex(key, 0); } ZEND_HASH_FOREACH_END_DEL(); ZEND_HASH_REVERSE_FOREACH_STR_KEY_VAL(EG(function_table), key, zv) { zend_function *func = Z_PTR_P(zv); @@ -349,7 +335,7 @@ void shutdown_executor(void) /* {{{ */ break; } destroy_op_array(&func->op_array); - zend_string_release(key); + zend_string_release_ex(key, 0); } ZEND_HASH_FOREACH_END_DEL(); ZEND_HASH_REVERSE_FOREACH_STR_KEY_VAL(EG(class_table), key, zv) { zend_class_entry *ce = Z_PTR_P(zv); @@ -357,7 +343,7 @@ void shutdown_executor(void) /* {{{ */ break; } destroy_zend_class(zv); - zend_string_release(key); + zend_string_release_ex(key, 0); } ZEND_HASH_FOREACH_END_DEL(); } @@ -528,107 +514,64 @@ ZEND_API zend_bool zend_is_executing(void) /* {{{ */ } /* }}} */ -ZEND_API void _zval_ptr_dtor(zval *zval_ptr ZEND_FILE_LINE_DC) /* {{{ */ +ZEND_API int zend_use_undefined_constant(zend_string *name, zend_ast_attr attr, zval *result) /* {{{ */ { - i_zval_ptr_dtor(zval_ptr ZEND_FILE_LINE_RELAY_CC); -} -/* }}} */ + char *colon; -ZEND_API void _zval_internal_ptr_dtor(zval *zval_ptr ZEND_FILE_LINE_DC) /* {{{ */ -{ - if (Z_REFCOUNTED_P(zval_ptr)) { - Z_DELREF_P(zval_ptr); - if (Z_REFCOUNT_P(zval_ptr) == 0) { - _zval_internal_dtor_for_ptr(zval_ptr ZEND_FILE_LINE_CC); + if (UNEXPECTED(EG(exception))) { + return FAILURE; + } else if ((colon = (char*)zend_memrchr(ZSTR_VAL(name), ':', ZSTR_LEN(name)))) { + zend_throw_error(NULL, "Undefined class constant '%s'", ZSTR_VAL(name)); + return FAILURE; + } else if ((attr & IS_CONSTANT_UNQUALIFIED) == 0) { + zend_throw_error(NULL, "Undefined constant '%s'", ZSTR_VAL(name)); + return FAILURE; + } else { + char *actual = ZSTR_VAL(name); + size_t actual_len = ZSTR_LEN(name); + char *slash = (char *) zend_memrchr(actual, '\\', actual_len); + + if (slash) { + actual = slash + 1; + actual_len -= (actual - ZSTR_VAL(name)); + } + + zend_error(E_WARNING, "Use of undefined constant %s - assumed '%s' (this will throw an Error in a future version of PHP)", actual, actual); + if (EG(exception)) { + return FAILURE; + } else { + zend_string *result_str = zend_string_init(actual, actual_len, 0); + zval_ptr_dtor_nogc(result); + ZVAL_NEW_STR(result, result_str); } } + return SUCCESS; } /* }}} */ ZEND_API int zval_update_constant_ex(zval *p, zend_class_entry *scope) /* {{{ */ { - zval *const_value; - char *colon; - zend_bool inline_change; - - if (Z_TYPE_P(p) == IS_CONSTANT) { - if (IS_CONSTANT_VISITED(p)) { - zend_throw_error(NULL, "Cannot declare self-referencing constant '%s'", Z_STRVAL_P(p)); - return FAILURE; - } - inline_change = (Z_TYPE_FLAGS_P(p) & IS_TYPE_REFCOUNTED) != 0; - SEPARATE_ZVAL_NOREF(p); - MARK_CONSTANT_VISITED(p); - if (Z_CONST_FLAGS_P(p) & IS_CONSTANT_CLASS) { - ZEND_ASSERT(EG(current_execute_data)); - if (inline_change) { - zend_string_release(Z_STR_P(p)); - } - if (scope && scope->name) { - ZVAL_STR_COPY(p, scope->name); - } else { - ZVAL_EMPTY_STRING(p); - } - } else if (UNEXPECTED((const_value = zend_get_constant_ex(Z_STR_P(p), scope, Z_CONST_FLAGS_P(p))) == NULL)) { - if (UNEXPECTED(EG(exception))) { - RESET_CONSTANT_VISITED(p); - return FAILURE; - } else if ((colon = (char*)zend_memrchr(Z_STRVAL_P(p), ':', Z_STRLEN_P(p)))) { - zend_throw_error(NULL, "Undefined class constant '%s'", Z_STRVAL_P(p)); - RESET_CONSTANT_VISITED(p); - return FAILURE; - } else { - if ((Z_CONST_FLAGS_P(p) & IS_CONSTANT_UNQUALIFIED) == 0) { - zend_throw_error(NULL, "Undefined constant '%s'", Z_STRVAL_P(p)); - RESET_CONSTANT_VISITED(p); - return FAILURE; - } else { - zend_string *save = Z_STR_P(p); - char *actual = Z_STRVAL_P(p); - size_t actual_len = Z_STRLEN_P(p); - char *slash = (char *) zend_memrchr(actual, '\\', actual_len); - if (slash) { - actual = slash + 1; - actual_len -= (actual - Z_STRVAL_P(p)); - } + if (Z_TYPE_P(p) == IS_CONSTANT_AST) { + zend_ast *ast = Z_ASTVAL_P(p); - zend_error(E_WARNING, "Use of undefined constant %s - assumed '%s' (this will throw an Error in a future version of PHP)", actual, actual); - if (EG(exception)) { - RESET_CONSTANT_VISITED(p); - return FAILURE; - } + if (ast->kind == ZEND_AST_CONSTANT) { + zend_string *name = zend_ast_get_constant_name(ast); + zval *zv = zend_get_constant_ex(name, scope, ast->attr); - if (!inline_change) { - ZVAL_STRINGL(p, actual, actual_len); - } else { - if (slash) { - ZVAL_STRINGL(p, actual, actual_len); - zend_string_release(save); - } else { - Z_TYPE_INFO_P(p) = Z_REFCOUNTED_P(p) ? - IS_STRING_EX : IS_INTERNED_STRING_EX; - } - } - } + if (UNEXPECTED(zv == NULL)) { + return zend_use_undefined_constant(name, ast->attr, p); } + zval_ptr_dtor_nogc(p); + ZVAL_COPY_OR_DUP(p, zv); } else { - if (inline_change) { - zend_string_release(Z_STR_P(p)); - } - ZVAL_COPY_VALUE(p, const_value); - zval_opt_copy_ctor(p); - } - } else if (Z_TYPE_P(p) == IS_CONSTANT_AST) { - zval tmp; + zval tmp; - inline_change = (Z_TYPE_FLAGS_P(p) & IS_TYPE_REFCOUNTED) != 0; - if (UNEXPECTED(zend_ast_evaluate(&tmp, Z_ASTVAL_P(p), scope) != SUCCESS)) { - return FAILURE; - } - if (inline_change) { - zval_ptr_dtor(p); + if (UNEXPECTED(zend_ast_evaluate(&tmp, ast, scope) != SUCCESS)) { + return FAILURE; + } + zval_ptr_dtor_nogc(p); + ZVAL_COPY_VALUE(p, &tmp); } - ZVAL_COPY_VALUE(p, &tmp); } return SUCCESS; } @@ -673,13 +616,7 @@ int zend_call_function(zend_fcall_info *fci, zend_fcall_info_cache *fci_cache) / return FAILURE; /* we would result in an instable executor otherwise */ } - switch (fci->size) { - case sizeof(zend_fcall_info): - break; /* nothing to do currently */ - default: - zend_error_noreturn(E_CORE_ERROR, "Corrupted fcall_info provided to zend_call_function()"); - break; - } + ZEND_ASSERT(fci->size == sizeof(zend_fcall_info)); /* Initialize execute_data */ if (!EG(current_execute_data)) { @@ -704,7 +641,7 @@ int zend_call_function(zend_fcall_info *fci, zend_fcall_info_cache *fci_cache) / EG(current_execute_data) = &dummy_execute_data; } - if (!fci_cache || !fci_cache->initialized) { + if (!fci_cache || !fci_cache->function_handler) { char *error = NULL; if (!fci_cache) { @@ -717,7 +654,7 @@ int zend_call_function(zend_fcall_info *fci, zend_fcall_info_cache *fci_cache) / = zend_get_callable_name_ex(&fci->function_name, fci->object); zend_error(E_WARNING, "Invalid callback %s, %s", ZSTR_VAL(callable_name), error); efree(error); - zend_string_release(callable_name); + zend_string_release_ex(callable_name, 0); } if (EG(current_execute_data) == &dummy_execute_data) { EG(current_execute_data) = dummy_execute_data.prev_execute_data; @@ -803,8 +740,7 @@ int zend_call_function(zend_fcall_info *fci, zend_fcall_info_cache *fci_cache) / if (UNEXPECTED(func->op_array.fn_flags & ZEND_ACC_CLOSURE)) { uint32_t call_info; - ZEND_ASSERT(GC_TYPE((zend_object*)func->op_array.prototype) == IS_OBJECT); - GC_REFCOUNT((zend_object*)func->op_array.prototype)++; + GC_ADDREF(ZEND_CLOSURE_OBJECT(func)); call_info = ZEND_CALL_CLOSURE; if (func->common.fn_flags & ZEND_ACC_FAKE_CLOSURE) { call_info |= ZEND_CALL_FAKE_CLOSURE; @@ -821,7 +757,7 @@ int zend_call_function(zend_fcall_info *fci, zend_fcall_info_cache *fci_cache) / EG(opline_before_exception) = current_opline_before_exception; if (call_via_handler) { /* We must re-initialize function again */ - fci_cache->initialized = 0; + fci_cache->function_handler = NULL; } } else if (func->type == ZEND_INTERNAL_FUNCTION) { int call_via_handler = (func->common.fn_flags & ZEND_ACC_CALL_VIA_TRAMPOLINE) != 0; @@ -845,7 +781,7 @@ int zend_call_function(zend_fcall_info *fci, zend_fcall_info_cache *fci_cache) / if (call_via_handler) { /* We must re-initialize function again */ - fci_cache->initialized = 0; + fci_cache->function_handler = NULL; } } else { /* ZEND_OVERLOADED_FUNCTION */ ZVAL_NULL(fci->retval); @@ -863,7 +799,7 @@ int zend_call_function(zend_fcall_info *fci, zend_fcall_info_cache *fci_cache) / zend_vm_stack_free_args(call); if (func->type == ZEND_OVERLOADED_FUNCTION_TEMPORARY) { - zend_string_release(func->common.function_name); + zend_string_release_ex(func->common.function_name, 0); } efree(func); @@ -895,7 +831,7 @@ int zend_call_function(zend_fcall_info *fci, zend_fcall_info_cache *fci_cache) / ZEND_API zend_class_entry *zend_lookup_class_ex(zend_string *name, const zval *key, int use_autoload) /* {{{ */ { zend_class_entry *ce = NULL; - zval args[1]; + zval args[1], *zv; zval local_retval; zend_string *lc_name; zend_fcall_info fcall_info; @@ -916,12 +852,12 @@ ZEND_API zend_class_entry *zend_lookup_class_ex(zend_string *name, const zval *k } } - ce = zend_hash_find_ptr(EG(class_table), lc_name); - if (ce) { + zv = zend_hash_find(EG(class_table), lc_name); + if (zv) { if (!key) { - zend_string_release(lc_name); + zend_string_release_ex(lc_name, 0); } - return ce; + return (zend_class_entry*)Z_PTR_P(zv); } /* The compiler is not-reentrant. Make sure we __autoload() only during run-time @@ -929,18 +865,19 @@ ZEND_API zend_class_entry *zend_lookup_class_ex(zend_string *name, const zval *k */ if (!use_autoload || zend_is_compiling()) { if (!key) { - zend_string_release(lc_name); + zend_string_release_ex(lc_name, 0); } return NULL; } if (!EG(autoload_func)) { - zend_function *func = zend_hash_find_ptr(EG(function_table), ZSTR_KNOWN(ZEND_STR_MAGIC_AUTOLOAD)); + zend_function *func = zend_fetch_function(ZSTR_KNOWN(ZEND_STR_MAGIC_AUTOLOAD)); + if (func) { EG(autoload_func) = func; } else { if (!key) { - zend_string_release(lc_name); + zend_string_release_ex(lc_name, 0); } return NULL; } @@ -949,7 +886,7 @@ ZEND_API zend_class_entry *zend_lookup_class_ex(zend_string *name, const zval *k /* Verify class name before passing it to __autoload() */ if (!key && strspn(ZSTR_VAL(name), "0123456789_abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ\200\201\202\203\204\205\206\207\210\211\212\213\214\215\216\217\220\221\222\223\224\225\226\227\230\231\232\233\234\235\236\237\240\241\242\243\244\245\246\247\250\251\252\253\254\255\256\257\260\261\262\263\264\265\266\267\270\271\272\273\274\275\276\277\300\301\302\303\304\305\306\307\310\311\312\313\314\315\316\317\320\321\322\323\324\325\326\327\330\331\332\333\334\335\336\337\340\341\342\343\344\345\346\347\350\351\352\353\354\355\356\357\360\361\362\363\364\365\366\367\370\371\372\373\374\375\376\377\\") != ZSTR_LEN(name)) { - zend_string_release(lc_name); + zend_string_release_ex(lc_name, 0); return NULL; } @@ -960,7 +897,7 @@ ZEND_API zend_class_entry *zend_lookup_class_ex(zend_string *name, const zval *k if (zend_hash_add_empty_element(EG(in_autoload), lc_name) == NULL) { if (!key) { - zend_string_release(lc_name); + zend_string_release_ex(lc_name, 0); } return NULL; } @@ -981,9 +918,7 @@ ZEND_API zend_class_entry *zend_lookup_class_ex(zend_string *name, const zval *k fcall_info.object = NULL; fcall_info.no_separation = 1; - fcall_cache.initialized = 1; fcall_cache.function_handler = EG(autoload_func); - fcall_cache.calling_scope = NULL; fcall_cache.called_scope = NULL; fcall_cache.object = NULL; @@ -994,14 +929,14 @@ ZEND_API zend_class_entry *zend_lookup_class_ex(zend_string *name, const zval *k zend_exception_restore(); zval_ptr_dtor(&args[0]); - zval_dtor(&fcall_info.function_name); + zval_ptr_dtor_str(&fcall_info.function_name); zend_hash_del(EG(in_autoload), lc_name); zval_ptr_dtor(&local_retval); if (!key) { - zend_string_release(lc_name); + zend_string_release_ex(lc_name, 0); } return ce; } @@ -1055,7 +990,7 @@ ZEND_API int zend_eval_stringl(char *str, size_t str_len, zval *retval_ptr, char int retval; if (retval_ptr) { - ZVAL_NEW_STR(&pv, zend_string_alloc(str_len + sizeof("return ;")-1, 1)); + ZVAL_NEW_STR(&pv, zend_string_alloc(str_len + sizeof("return ;")-1, 0)); memcpy(Z_STRVAL(pv), "return ", sizeof("return ") - 1); memcpy(Z_STRVAL(pv) + sizeof("return ") - 1, str, str_len); Z_STRVAL(pv)[Z_STRLEN(pv) - 1] = ';'; @@ -1106,7 +1041,7 @@ ZEND_API int zend_eval_stringl(char *str, size_t str_len, zval *retval_ptr, char } else { retval = FAILURE; } - zval_dtor(&pv); + zval_ptr_dtor_str(&pv); return retval; } /* }}} */ @@ -1530,12 +1465,11 @@ ZEND_API zend_array *zend_rebuild_symbol_table(void) /* {{{ */ } zend_hash_extend(symbol_table, ex->func->op_array.last_var, 0); } else { - symbol_table = ex->symbol_table = emalloc(sizeof(zend_array)); - zend_hash_init(symbol_table, ex->func->op_array.last_var, NULL, ZVAL_PTR_DTOR, 0); + symbol_table = ex->symbol_table = zend_new_array(ex->func->op_array.last_var); if (!ex->func->op_array.last_var) { return symbol_table; } - zend_hash_real_init(symbol_table, 0); + zend_hash_real_init_mixed(symbol_table); /*printf("Cache miss! Initialized %x\n", EG(active_symbol_table));*/ } if (EXPECTED(ex->func->op_array.last_var)) { @@ -1566,7 +1500,7 @@ ZEND_API void zend_attach_symbol_table(zend_execute_data *execute_data) /* {{{ * zval *var = EX_VAR_NUM(0); do { - zval *zv = zend_hash_find(ht, *str); + zval *zv = zend_hash_find_ex(ht, *str, 1); if (zv) { if (Z_TYPE_P(zv) == IS_INDIRECT) { @@ -1632,8 +1566,7 @@ ZEND_API int zend_set_local_var(zend_string *name, zval *value, int force) /* {{ do { if (ZSTR_H(*str) == h && - ZSTR_LEN(*str) == ZSTR_LEN(name) && - memcmp(ZSTR_VAL(*str), ZSTR_VAL(name), ZSTR_LEN(name)) == 0) { + zend_string_equal_content(*str, name)) { zval *var = EX_VAR_NUM(str - op_array->vars); ZVAL_COPY_VALUE(var, value); return SUCCESS; @@ -1644,11 +1577,13 @@ ZEND_API int zend_set_local_var(zend_string *name, zval *value, int force) /* {{ if (force) { zend_array *symbol_table = zend_rebuild_symbol_table(); if (symbol_table) { - return zend_hash_update(symbol_table, name, value) ? SUCCESS : FAILURE; + zend_hash_update(symbol_table, name, value); + return SUCCESS; } } } else { - return (zend_hash_update_ind(execute_data->symbol_table, name, value) != NULL) ? SUCCESS : FAILURE; + zend_hash_update_ind(execute_data->symbol_table, name, value); + return SUCCESS; } } return FAILURE; @@ -1686,11 +1621,13 @@ ZEND_API int zend_set_local_var_str(const char *name, size_t len, zval *value, i if (force) { zend_array *symbol_table = zend_rebuild_symbol_table(); if (symbol_table) { - return zend_hash_str_update(symbol_table, name, len, value) ? SUCCESS : FAILURE; + zend_hash_str_update(symbol_table, name, len, value); + return SUCCESS; } } } else { - return (zend_hash_str_update_ind(execute_data->symbol_table, name, len, value) != NULL) ? SUCCESS : FAILURE; + zend_hash_str_update_ind(execute_data->symbol_table, name, len, value); + return SUCCESS; } } return FAILURE; |