diff options
Diffstat (limited to 'Zend/zend_execute_API.c')
-rw-r--r-- | Zend/zend_execute_API.c | 179 |
1 files changed, 84 insertions, 95 deletions
diff --git a/Zend/zend_execute_API.c b/Zend/zend_execute_API.c index a551449e79..4c4dbc8891 100644 --- a/Zend/zend_execute_API.c +++ b/Zend/zend_execute_API.c @@ -2,7 +2,7 @@ +----------------------------------------------------------------------+ | Zend Engine | +----------------------------------------------------------------------+ - | Copyright (c) 1998-2018 Zend Technologies Ltd. (http://www.zend.com) | + | Copyright (c) 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 | @@ -33,6 +33,7 @@ #include "zend_generators.h" #include "zend_vm.h" #include "zend_float.h" +#include "zend_weakrefs.h" #ifdef HAVE_SYS_TIME_H #include <sys/time.h> #endif @@ -183,6 +184,8 @@ void init_executor(void) /* {{{ */ EG(persistent_functions_count) = EG(function_table)->nNumUsed; EG(persistent_classes_count) = EG(class_table)->nNumUsed; + zend_weakrefs_init(); + EG(active) = 1; } /* }}} */ @@ -205,7 +208,7 @@ static void zend_unclean_zval_ptr_dtor(zval *zv) /* {{{ */ if (Z_TYPE_P(zv) == IS_INDIRECT) { zv = Z_INDIRECT_P(zv); } - i_zval_ptr_dtor(zv ZEND_FILE_LINE_CC); + i_zval_ptr_dtor(zv); } /* }}} */ @@ -265,8 +268,20 @@ void shutdown_executor(void) /* {{{ */ zend_close_rsrc_list(&EG(regular_list)); } zend_end_try(); + if (!fast_shutdown) { + zend_hash_graceful_reverse_destroy(&EG(symbol_table)); + +#if ZEND_DEBUG + if (gc_enabled() && !CG(unclean_shutdown)) { + gc_collect_cycles(); + } +#endif + } + zend_objects_store_free_object_storage(&EG(objects_store), fast_shutdown); + zend_weakrefs_shutdown(); + /* All resources and objects are destroyed. */ /* No PHP callback functions may be called after this point. */ EG(active) = 0; @@ -286,14 +301,6 @@ void shutdown_executor(void) /* {{{ */ 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_enabled() && !CG(unclean_shutdown)) { - gc_collect_cycles(); - } -#endif - /* remove error handlers before destroying classes and functions, * so that if handler used some class, crash would not happen */ if (Z_TYPE(EG(user_error_handler)) != IS_UNDEF) { @@ -319,7 +326,7 @@ 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 (ZEND_CONSTANT_FLAGS(c) & CONST_PERSISTENT) { + if (_idx == EG(persistent_constants_count)) { break; } zval_ptr_dtor_nogc(&c->value); @@ -329,22 +336,65 @@ void shutdown_executor(void) /* {{{ */ efree(c); 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); - if (func->type == ZEND_INTERNAL_FUNCTION) { + if (_idx == EG(persistent_functions_count)) { break; } destroy_op_array(&func->op_array); zend_string_release_ex(key, 0); } ZEND_HASH_FOREACH_END_DEL(); + + /* Cleanup preloaded immutable functions */ + ZEND_HASH_REVERSE_FOREACH_VAL(EG(function_table), zv) { + zend_op_array *op_array = Z_PTR_P(zv); + if (op_array->type == ZEND_INTERNAL_FUNCTION) { + break; + } + ZEND_ASSERT(op_array->fn_flags & ZEND_ACC_IMMUTABLE); + if (op_array->static_variables) { + HashTable *ht = ZEND_MAP_PTR_GET(op_array->static_variables_ptr); + if (ht) { + ZEND_ASSERT(GC_REFCOUNT(ht) == 1); + zend_array_destroy(ht); + } + } + } ZEND_HASH_FOREACH_END(); + ZEND_HASH_REVERSE_FOREACH_STR_KEY_VAL(EG(class_table), key, zv) { - zend_class_entry *ce = Z_PTR_P(zv); - if (ce->type == ZEND_INTERNAL_CLASS) { + if (_idx == EG(persistent_classes_count)) { break; } destroy_zend_class(zv); zend_string_release_ex(key, 0); } ZEND_HASH_FOREACH_END_DEL(); + + /* Cleanup preloaded immutable classes */ + 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_ASSERT(ce->ce_flags & ZEND_ACC_IMMUTABLE); + if (ce->default_static_members_count) { + zend_cleanup_internal_class_data(ce); + } + if (ce->ce_flags & ZEND_HAS_STATIC_IN_METHODS) { + zend_op_array *op_array; + ZEND_HASH_FOREACH_PTR(&ce->function_table, op_array) { + if (op_array->type == ZEND_USER_FUNCTION) { + if (op_array->static_variables) { + HashTable *ht = ZEND_MAP_PTR_GET(op_array->static_variables_ptr); + if (ht) { + ZEND_ASSERT(GC_REFCOUNT(ht) == 1); + zend_array_destroy(ht); + } + } + } + } ZEND_HASH_FOREACH_END(); + } + } ZEND_HASH_FOREACH_END(); } zend_cleanup_internal_classes(); @@ -605,6 +655,8 @@ int zend_call_function(zend_fcall_info *fci, zend_fcall_info_cache *fci_cache) / zend_execute_data *call, dummy_execute_data; zend_fcall_info_cache fci_cache_local; zend_function *func; + uint32_t call_info; + void *object_or_called_scope; ZVAL_UNDEF(fci->retval); @@ -677,11 +729,18 @@ int zend_call_function(zend_fcall_info *fci, zend_fcall_info_cache *fci_cache) / } func = fci_cache->function_handler; - fci->object = (func->common.fn_flags & ZEND_ACC_STATIC) ? - NULL : fci_cache->object; + if ((func->common.fn_flags & ZEND_ACC_STATIC) || !fci_cache->object) { + fci->object = NULL; + object_or_called_scope = fci_cache->called_scope; + call_info = ZEND_CALL_TOP_FUNCTION | ZEND_CALL_DYNAMIC; + } else { + fci->object = fci_cache->object; + object_or_called_scope = fci->object; + call_info = ZEND_CALL_TOP_FUNCTION | ZEND_CALL_DYNAMIC | ZEND_CALL_HAS_THIS; + } - call = zend_vm_stack_push_call_frame(ZEND_CALL_TOP_FUNCTION | ZEND_CALL_DYNAMIC, - func, fci->param_count, fci_cache->called_scope, fci->object); + call = zend_vm_stack_push_call_frame(call_info, + func, fci->param_count, object_or_called_scope); if (UNEXPECTED(func->common.fn_flags & ZEND_ACC_DEPRECATED)) { zend_error(E_DEPRECATED, "Function %s%s%s() is deprecated", @@ -763,7 +822,6 @@ int zend_call_function(zend_fcall_info *fci, zend_fcall_info_cache *fci_cache) / int call_via_handler = (func->common.fn_flags & ZEND_ACC_CALL_VIA_TRAMPOLINE) != 0; ZVAL_NULL(fci->retval); call->prev_execute_data = EG(current_execute_data); - call->return_value = NULL; /* this is not a constructor call */ EG(current_execute_data) = call; if (EXPECTED(zend_execute_internal == NULL)) { /* saves one function call if zend_execute_internal is not used */ @@ -828,7 +886,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_API zend_class_entry *zend_lookup_class_ex(zend_string *name, zend_string *key, int use_autoload) /* {{{ */ { zend_class_entry *ce = NULL; zval args[1], *zv; @@ -838,7 +896,7 @@ ZEND_API zend_class_entry *zend_lookup_class_ex(zend_string *name, const zval *k zend_fcall_info_cache fcall_cache; if (key) { - lc_name = Z_STR_P(key); + lc_name = key; } else { if (name == NULL || !ZSTR_LEN(name)) { return NULL; @@ -1073,7 +1131,7 @@ ZEND_API int zend_eval_string_ex(char *str, zval *retval_ptr, char *string_name, static void zend_set_timeout_ex(zend_long seconds, int reset_signals); -ZEND_API ZEND_NORETURN void zend_timeout(int dummy) /* {{{ */ +ZEND_API ZEND_NORETURN void ZEND_FASTCALL zend_timeout(int dummy) /* {{{ */ { #if defined(PHP_WIN32) # ifndef ZTS @@ -1126,7 +1184,7 @@ static void zend_timeout_handler(int dummy) /* {{{ */ output_len = snprintf(log_buffer, sizeof(log_buffer), "\nFatal error: Maximum execution time of " ZEND_LONG_FMT "+" ZEND_LONG_FMT " seconds exceeded (terminated) in %s on line %d\n", EG(timeout_seconds), EG(hard_timeout), error_filename, error_lineno); if (output_len > 0) { - write(2, log_buffer, MIN(output_len, sizeof(log_buffer))); + zend_quiet_write(2, log_buffer, MIN(output_len, sizeof(log_buffer))); } _exit(124); } @@ -1193,7 +1251,7 @@ static void zend_set_timeout_ex(zend_long seconds, int reset_signals) /* {{{ */ timer, so we could end up with just an ignored timeout. Instead delete and recreate. */ if (NULL != tq_timer) { - if (!DeleteTimerQueueTimer(NULL, tq_timer, NULL)) { + if (!DeleteTimerQueueTimer(NULL, tq_timer, INVALID_HANDLE_VALUE)) { tq_timer = NULL; zend_error_noreturn(E_ERROR, "Could not delete queued timer"); return; @@ -1267,7 +1325,7 @@ void zend_unset_timeout(void) /* {{{ */ { #ifdef ZEND_WIN32 if (NULL != tq_timer) { - if (!DeleteTimerQueueTimer(NULL, tq_timer, NULL)) { + if (!DeleteTimerQueueTimer(NULL, tq_timer, INVALID_HANDLE_VALUE)) { EG(timed_out) = 0; tq_timer = NULL; zend_error_noreturn(E_ERROR, "Could not delete queued timer"); @@ -1352,7 +1410,7 @@ check_fetch_type: } /* }}} */ -zend_class_entry *zend_fetch_class_by_name(zend_string *class_name, const zval *key, int fetch_type) /* {{{ */ +zend_class_entry *zend_fetch_class_by_name(zend_string *class_name, zend_string *key, int fetch_type) /* {{{ */ { zend_class_entry *ce; @@ -1374,65 +1432,6 @@ zend_class_entry *zend_fetch_class_by_name(zend_string *class_name, const zval * } /* }}} */ -#define MAX_ABSTRACT_INFO_CNT 3 -#define MAX_ABSTRACT_INFO_FMT "%s%s%s%s" -#define DISPLAY_ABSTRACT_FN(idx) \ - ai.afn[idx] ? ZEND_FN_SCOPE_NAME(ai.afn[idx]) : "", \ - ai.afn[idx] ? "::" : "", \ - ai.afn[idx] ? ZSTR_VAL(ai.afn[idx]->common.function_name) : "", \ - ai.afn[idx] && ai.afn[idx + 1] ? ", " : (ai.afn[idx] && ai.cnt > MAX_ABSTRACT_INFO_CNT ? ", ..." : "") - -typedef struct _zend_abstract_info { - zend_function *afn[MAX_ABSTRACT_INFO_CNT + 1]; - int cnt; - int ctor; -} zend_abstract_info; - -static void zend_verify_abstract_class_function(zend_function *fn, zend_abstract_info *ai) /* {{{ */ -{ - if (fn->common.fn_flags & ZEND_ACC_ABSTRACT) { - if (ai->cnt < MAX_ABSTRACT_INFO_CNT) { - ai->afn[ai->cnt] = fn; - } - if (fn->common.fn_flags & ZEND_ACC_CTOR) { - if (!ai->ctor) { - ai->cnt++; - ai->ctor = 1; - } else { - ai->afn[ai->cnt] = NULL; - } - } else { - ai->cnt++; - } - } -} -/* }}} */ - -void zend_verify_abstract_class(zend_class_entry *ce) /* {{{ */ -{ - zend_function *func; - zend_abstract_info ai; - - if ((ce->ce_flags & ZEND_ACC_IMPLICIT_ABSTRACT_CLASS) && !(ce->ce_flags & (ZEND_ACC_TRAIT | ZEND_ACC_EXPLICIT_ABSTRACT_CLASS))) { - memset(&ai, 0, sizeof(ai)); - - ZEND_HASH_FOREACH_PTR(&ce->function_table, func) { - zend_verify_abstract_class_function(func, &ai); - } ZEND_HASH_FOREACH_END(); - - if (ai.cnt) { - zend_error_noreturn(E_ERROR, "Class %s contains %d abstract method%s and must therefore be declared abstract or implement the remaining methods (" MAX_ABSTRACT_INFO_FMT MAX_ABSTRACT_INFO_FMT MAX_ABSTRACT_INFO_FMT ")", - ZSTR_VAL(ce->name), ai.cnt, - ai.cnt > 1 ? "s" : "", - DISPLAY_ABSTRACT_FN(0), - DISPLAY_ABSTRACT_FN(1), - DISPLAY_ABSTRACT_FN(2) - ); - } - } -} -/* }}} */ - ZEND_API int zend_delete_global_variable(zend_string *name) /* {{{ */ { return zend_hash_del_ind(&EG(symbol_table), name); @@ -1647,13 +1646,3 @@ ZEND_API int zend_forbid_dynamic_call(const char *func_name) /* {{{ */ return SUCCESS; } /* }}} */ - -/* - * Local variables: - * tab-width: 4 - * c-basic-offset: 4 - * indent-tabs-mode: t - * End: - * vim600: sw=4 ts=4 fdm=marker - * vim<600: sw=4 ts=4 - */ |