diff options
Diffstat (limited to 'Zend/zend_execute_API.c')
-rw-r--r-- | Zend/zend_execute_API.c | 335 |
1 files changed, 162 insertions, 173 deletions
diff --git a/Zend/zend_execute_API.c b/Zend/zend_execute_API.c index 6eb9dfacee..e1001062e5 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,8 @@ #include "zend_generators.h" #include "zend_vm.h" #include "zend_float.h" +#include "zend_weakrefs.h" +#include "zend_inheritance.h" #ifdef HAVE_SYS_TIME_H #include <sys/time.h> #endif @@ -130,8 +132,8 @@ void init_executor(void) /* {{{ */ original_sigsegv_handler = signal(SIGSEGV, zend_handle_sigsegv); #endif - EG(symtable_cache_ptr) = EG(symtable_cache) - 1; - EG(symtable_cache_limit) = EG(symtable_cache) + SYMTABLE_CACHE_SIZE - 1; + EG(symtable_cache_ptr) = EG(symtable_cache); + EG(symtable_cache_limit) = EG(symtable_cache) + SYMTABLE_CACHE_SIZE; EG(no_extensions) = 0; EG(function_table) = CG(function_table); @@ -183,6 +185,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,11 +209,11 @@ 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); } /* }}} */ -static void zend_throw_or_error(int fetch_type, zend_class_entry *exception_ce, const char *format, ...) /* {{{ */ +static ZEND_COLD void zend_throw_or_error(int fetch_type, zend_class_entry *exception_ce, const char *format, ...) /* {{{ */ { va_list va; char *message = NULL; @@ -261,41 +265,57 @@ void shutdown_executor(void) /* {{{ */ zend_llist_destroy(&CG(open_files)); } zend_end_try(); + EG(flags) |= EG_FLAGS_IN_RESOURCE_SHUTDOWN; zend_try { zend_close_rsrc_list(&EG(regular_list)); } zend_end_try(); - zend_objects_store_free_object_storage(&EG(objects_store), fast_shutdown); - - /* All resources and objects are destroyed. */ - /* No PHP callback functions may be called after this point. */ + /* No PHP callback functions should be called after this point. */ EG(active) = 0; - zend_try { - zend_llist_apply(&zend_extensions, (llist_apply_func_t) zend_extension_deactivator); - } zend_end_try(); - - if (fast_shutdown) { - /* Fast Request Shutdown - * ===================== - * Zend Memory Manager frees memory by its own. We don't have to free - * each allocated block separately. - */ - 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 { + if (!fast_shutdown) { zend_hash_graceful_reverse_destroy(&EG(symbol_table)); -#if ZEND_DEBUG - if (gc_enabled() && !CG(unclean_shutdown)) { - gc_collect_cycles(); - } -#endif + /* Release static properties and static variables prior to the final GC run, + * as they may hold GC roots. */ + 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; + } + 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_MAP_PTR_SET(op_array->static_variables_ptr, NULL); + } + } + } ZEND_HASH_FOREACH_END(); + ZEND_HASH_REVERSE_FOREACH_VAL(EG(class_table), zv) { + zend_class_entry *ce = Z_PTR_P(zv); + 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) { + if (!(GC_FLAGS(ht) & IS_ARRAY_IMMUTABLE) && GC_DELREF(ht) == 0) { + zend_array_destroy(ht); + } + ZEND_MAP_PTR_SET(op_array->static_variables_ptr, NULL); + } + } + } + } ZEND_HASH_FOREACH_END(); + } + } ZEND_HASH_FOREACH_END(); - /* remove error handlers before destroying classes and functions, - * so that if handler used some class, crash would not happen */ + /* Also release error and exception handlers, which may hold objects. */ if (Z_TYPE(EG(user_error_handler)) != IS_UNDEF) { zval_ptr_dtor(&EG(user_error_handler)); ZVAL_UNDEF(&EG(user_error_handler)); @@ -310,6 +330,32 @@ void shutdown_executor(void) /* {{{ */ zend_stack_clean(&EG(user_error_handlers), (void (*)(void *))ZVAL_PTR_DTOR, 1); zend_stack_clean(&EG(user_exception_handlers), (void (*)(void *))ZVAL_PTR_DTOR, 1); +#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(); + + zend_try { + zend_llist_apply(&zend_extensions, (llist_apply_func_t) zend_extension_deactivator); + } zend_end_try(); + + if (fast_shutdown) { + /* Fast Request Shutdown + * ===================== + * Zend Memory Manager frees memory by its own. We don't have to free + * each allocated block separately. + */ + 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_vm_stack_destroy(); if (EG(full_tables_cleanup)) { @@ -319,7 +365,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,17 +375,18 @@ 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(); + 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); @@ -347,12 +394,10 @@ void shutdown_executor(void) /* {{{ */ } ZEND_HASH_FOREACH_END_DEL(); } - zend_cleanup_internal_classes(); - - while (EG(symtable_cache_ptr)>=EG(symtable_cache)) { + while (EG(symtable_cache_ptr) > EG(symtable_cache)) { + EG(symtable_cache_ptr)--; zend_hash_destroy(*EG(symtable_cache_ptr)); FREE_HASHTABLE(*EG(symtable_cache_ptr)); - EG(symtable_cache_ptr)--; } zend_hash_destroy(&EG(included_files)); @@ -514,7 +559,7 @@ ZEND_API zend_bool zend_is_executing(void) /* {{{ */ } /* }}} */ -ZEND_API int zend_use_undefined_constant(zend_string *name, zend_ast_attr attr, zval *result) /* {{{ */ +ZEND_API ZEND_COLD int zend_use_undefined_constant(zend_string *name, zend_ast_attr attr, zval *result) /* {{{ */ { char *colon; @@ -605,6 +650,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 +724,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", @@ -692,6 +746,7 @@ int zend_call_function(zend_fcall_info *fci, zend_fcall_info_cache *fci_cache) / zend_vm_stack_free_call_frame(call); if (EG(current_execute_data) == &dummy_execute_data) { EG(current_execute_data) = dummy_execute_data.prev_execute_data; + zend_rethrow_exception(EG(current_execute_data)); } return FAILURE; } @@ -763,7 +818,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 +882,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, uint32_t flags) /* {{{ */ { zend_class_entry *ce = NULL; zval args[1], *zv; @@ -839,7 +893,7 @@ ZEND_API zend_class_entry *zend_lookup_class_ex(zend_string *name, const zval *k zend_class_entry *orig_fake_scope; if (key) { - lc_name = Z_STR_P(key); + lc_name = key; } else { if (name == NULL || !ZSTR_LEN(name)) { return NULL; @@ -858,13 +912,23 @@ ZEND_API zend_class_entry *zend_lookup_class_ex(zend_string *name, const zval *k if (!key) { zend_string_release_ex(lc_name, 0); } - return (zend_class_entry*)Z_PTR_P(zv); + ce = (zend_class_entry*)Z_PTR_P(zv); + if (UNEXPECTED(!(ce->ce_flags & ZEND_ACC_LINKED))) { + if ((flags & ZEND_FETCH_CLASS_ALLOW_UNLINKED) || + ((flags & ZEND_FETCH_CLASS_ALLOW_NEARLY_LINKED) && + (ce->ce_flags & ZEND_ACC_NEARLY_LINKED))) { + ce->ce_flags |= ZEND_ACC_HAS_UNLINKED_USES; + return ce; + } + return NULL; + } + return ce; } /* The compiler is not-reentrant. Make sure we __autoload() only during run-time * (doesn't impact functionality of __autoload() */ - if (!use_autoload || zend_is_compiling()) { + if ((flags & ZEND_FETCH_CLASS_NO_AUTOLOAD) || zend_is_compiling()) { if (!key) { zend_string_release_ex(lc_name, 0); } @@ -948,7 +1012,7 @@ ZEND_API zend_class_entry *zend_lookup_class_ex(zend_string *name, const zval *k ZEND_API zend_class_entry *zend_lookup_class(zend_string *name) /* {{{ */ { - return zend_lookup_class_ex(name, NULL, 1); + return zend_lookup_class_ex(name, NULL, 0); } /* }}} */ @@ -1077,7 +1141,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 @@ -1130,7 +1194,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); } @@ -1197,7 +1261,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; @@ -1212,8 +1276,7 @@ static void zend_set_timeout_ex(zend_long seconds, int reset_signals) /* {{{ */ zend_error_noreturn(E_ERROR, "Could not queue new timer"); return; } -#else -# ifdef HAVE_SETITIMER +#elif defined(HAVE_SETITIMER) { struct itimerval t_r; /* timeout requested */ int signo; @@ -1222,39 +1285,38 @@ static void zend_set_timeout_ex(zend_long seconds, int reset_signals) /* {{{ */ t_r.it_value.tv_sec = seconds; t_r.it_value.tv_usec = t_r.it_interval.tv_sec = t_r.it_interval.tv_usec = 0; -# ifdef __CYGWIN__ +# ifdef __CYGWIN__ setitimer(ITIMER_REAL, &t_r, NULL); } signo = SIGALRM; -# else +# else setitimer(ITIMER_PROF, &t_r, NULL); } signo = SIGPROF; -# endif +# endif if (reset_signals) { -# ifdef ZEND_SIGNALS +# ifdef ZEND_SIGNALS zend_signal(signo, zend_timeout_handler); -# else +# else sigset_t sigset; -# ifdef HAVE_SIGACTION +# ifdef HAVE_SIGACTION struct sigaction act; act.sa_handler = zend_timeout_handler; sigemptyset(&act.sa_mask); act.sa_flags = SA_RESETHAND | SA_NODEFER; sigaction(signo, &act, NULL); -# else +# else signal(signo, zend_timeout_handler); -# endif /* HAVE_SIGACTION */ +# endif /* HAVE_SIGACTION */ sigemptyset(&sigset); sigaddset(&sigset, signo); sigprocmask(SIG_UNBLOCK, &sigset, NULL); -# endif /* ZEND_SIGNALS */ +# endif /* ZEND_SIGNALS */ } } -# endif /* HAVE_SETITIMER */ -#endif +#endif /* HAVE_SETITIMER */ } /* }}} */ @@ -1271,7 +1333,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"); @@ -1279,23 +1341,20 @@ void zend_unset_timeout(void) /* {{{ */ } tq_timer = NULL; } - EG(timed_out) = 0; -#else -# ifdef HAVE_SETITIMER +#elif defined(HAVE_SETITIMER) if (EG(timeout_seconds)) { struct itimerval no_timeout; no_timeout.it_value.tv_sec = no_timeout.it_value.tv_usec = no_timeout.it_interval.tv_sec = no_timeout.it_interval.tv_usec = 0; -#ifdef __CYGWIN__ +# ifdef __CYGWIN__ setitimer(ITIMER_REAL, &no_timeout, NULL); -#else +# else setitimer(ITIMER_PROF, &no_timeout, NULL); -#endif +# endif } -# endif - EG(timed_out) = 0; #endif + EG(timed_out) = 0; } /* }}} */ @@ -1339,8 +1398,8 @@ check_fetch_type: } if (fetch_type & ZEND_FETCH_CLASS_NO_AUTOLOAD) { - return zend_lookup_class_ex(class_name, NULL, 0); - } else if ((ce = zend_lookup_class_ex(class_name, NULL, 1)) == NULL) { + return zend_lookup_class_ex(class_name, NULL, fetch_type); + } else if ((ce = zend_lookup_class_ex(class_name, NULL, fetch_type)) == NULL) { if (!(fetch_type & ZEND_FETCH_CLASS_SILENT) && !EG(exception)) { if (fetch_sub_type == ZEND_FETCH_CLASS_INTERFACE) { zend_throw_or_error(fetch_type, NULL, "Interface '%s' not found", ZSTR_VAL(class_name)); @@ -1356,84 +1415,39 @@ 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; if (fetch_type & ZEND_FETCH_CLASS_NO_AUTOLOAD) { - return zend_lookup_class_ex(class_name, key, 0); - } else if ((ce = zend_lookup_class_ex(class_name, key, 1)) == NULL) { - if ((fetch_type & ZEND_FETCH_CLASS_SILENT) == 0 && !EG(exception)) { - if ((fetch_type & ZEND_FETCH_CLASS_MASK) == ZEND_FETCH_CLASS_INTERFACE) { - zend_throw_or_error(fetch_type, NULL, "Interface '%s' not found", ZSTR_VAL(class_name)); - } else if ((fetch_type & ZEND_FETCH_CLASS_MASK) == ZEND_FETCH_CLASS_TRAIT) { - zend_throw_or_error(fetch_type, NULL, "Trait '%s' not found", ZSTR_VAL(class_name)); - } else { - zend_throw_or_error(fetch_type, NULL, "Class '%s' not found", ZSTR_VAL(class_name)); - } - } - return NULL; - } - return ce; -} -/* }}} */ - -#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; + return zend_lookup_class_ex(class_name, key, fetch_type); + } else if ((ce = zend_lookup_class_ex(class_name, key, fetch_type)) == NULL) { + if (fetch_type & ZEND_FETCH_CLASS_SILENT) { + return NULL; } - if (fn->common.fn_flags & ZEND_ACC_CTOR) { - if (!ai->ctor) { - ai->cnt++; - ai->ctor = 1; - } else { - ai->afn[ai->cnt] = NULL; + if (EG(exception)) { + if (!(fetch_type & ZEND_FETCH_CLASS_EXCEPTION)) { + zend_string *exception_str; + zval exception_zv; + ZVAL_OBJ(&exception_zv, EG(exception)); + Z_ADDREF(exception_zv); + zend_clear_exception(); + exception_str = zval_get_string(&exception_zv); + zend_error_noreturn(E_ERROR, + "During class fetch: Uncaught %s", ZSTR_VAL(exception_str)); } - } else { - ai->cnt++; + return NULL; } - } -} -/* }}} */ - -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) - ); + if ((fetch_type & ZEND_FETCH_CLASS_MASK) == ZEND_FETCH_CLASS_INTERFACE) { + zend_throw_or_error(fetch_type, NULL, "Interface '%s' not found", ZSTR_VAL(class_name)); + } else if ((fetch_type & ZEND_FETCH_CLASS_MASK) == ZEND_FETCH_CLASS_TRAIT) { + zend_throw_or_error(fetch_type, NULL, "Trait '%s' not found", ZSTR_VAL(class_name)); + } else { + zend_throw_or_error(fetch_type, NULL, "Class '%s' not found", ZSTR_VAL(class_name)); } + return NULL; } + return ce; } /* }}} */ @@ -1461,9 +1475,8 @@ ZEND_API zend_array *zend_rebuild_symbol_table(void) /* {{{ */ } ZEND_ADD_CALL_FLAG(ex, ZEND_CALL_HAS_SYMBOL_TABLE); - if (EG(symtable_cache_ptr) >= EG(symtable_cache)) { - /*printf("Cache hit! Reusing %x\n", symtable_cache[symtable_cache_ptr]);*/ - symbol_table = ex->symbol_table = *(EG(symtable_cache_ptr)--); + if (EG(symtable_cache_ptr) > EG(symtable_cache)) { + symbol_table = ex->symbol_table = *(--EG(symtable_cache_ptr)); if (!ex->func->op_array.last_var) { return symbol_table; } @@ -1637,27 +1650,3 @@ ZEND_API int zend_set_local_var_str(const char *name, size_t len, zval *value, i return FAILURE; } /* }}} */ - -ZEND_API int zend_forbid_dynamic_call(const char *func_name) /* {{{ */ -{ - zend_execute_data *ex = EG(current_execute_data); - ZEND_ASSERT(ex != NULL && ex->func != NULL); - - if (ZEND_CALL_INFO(ex) & ZEND_CALL_DYNAMIC) { - zend_error(E_WARNING, "Cannot call %s dynamically", func_name); - return FAILURE; - } - - 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 - */ |