diff options
Diffstat (limited to 'Zend/zend_execute_API.c')
-rw-r--r-- | Zend/zend_execute_API.c | 304 |
1 files changed, 134 insertions, 170 deletions
diff --git a/Zend/zend_execute_API.c b/Zend/zend_execute_API.c index 8688a9dcf9..e46d0d84ee 100644 --- a/Zend/zend_execute_API.c +++ b/Zend/zend_execute_API.c @@ -100,28 +100,21 @@ static void zend_extension_deactivator(zend_extension *extension) /* {{{ */ } /* }}} */ -static int clean_non_persistent_function(zval *zv) /* {{{ */ +static int clean_non_persistent_constant_full(zval *zv) /* {{{ */ { - zend_function *function = Z_PTR_P(zv); - return (function->type == ZEND_INTERNAL_FUNCTION) ? ZEND_HASH_APPLY_STOP : ZEND_HASH_APPLY_REMOVE; + zend_constant *c = Z_PTR_P(zv); + return (c->flags & CONST_PERSISTENT) ? ZEND_HASH_APPLY_KEEP : ZEND_HASH_APPLY_REMOVE; } /* }}} */ -ZEND_API int clean_non_persistent_function_full(zval *zv) /* {{{ */ +static int clean_non_persistent_function_full(zval *zv) /* {{{ */ { zend_function *function = Z_PTR_P(zv); return (function->type == ZEND_INTERNAL_FUNCTION) ? ZEND_HASH_APPLY_KEEP : ZEND_HASH_APPLY_REMOVE; } /* }}} */ -static int clean_non_persistent_class(zval *zv) /* {{{ */ -{ - zend_class_entry *ce = Z_PTR_P(zv); - return (ce->type == ZEND_INTERNAL_CLASS) ? ZEND_HASH_APPLY_STOP : ZEND_HASH_APPLY_REMOVE; -} -/* }}} */ - -ZEND_API int clean_non_persistent_class_full(zval *zv) /* {{{ */ +static int clean_non_persistent_class_full(zval *zv) /* {{{ */ { zend_class_entry *ce = Z_PTR_P(zv); return (ce->type == ZEND_INTERNAL_CLASS) ? ZEND_HASH_APPLY_KEEP : ZEND_HASH_APPLY_REMOVE; @@ -153,7 +146,6 @@ void init_executor(void) /* {{{ */ zend_vm_stack_init(); zend_hash_init(&EG(symbol_table), 64, NULL, ZVAL_PTR_DTOR, 0); - EG(valid_symbol_table) = 1; zend_llist_apply(&zend_extensions, (llist_apply_func_t) zend_extension_activator); @@ -162,6 +154,7 @@ void init_executor(void) /* {{{ */ EG(ticks_count) = 0; ZVAL_UNDEF(&EG(user_error_handler)); + ZVAL_UNDEF(&EG(user_exception_handler)); EG(current_execute_data) = NULL; @@ -185,6 +178,8 @@ void init_executor(void) /* {{{ */ EG(ht_iterators) = EG(ht_iterators_slots); memset(EG(ht_iterators), 0, sizeof(EG(ht_iterators_slots))); + EG(each_deprecation_thrown) = 0; + EG(active) = 1; } /* }}} */ @@ -251,139 +246,127 @@ void shutdown_destructors(void) /* {{{ */ void shutdown_executor(void) /* {{{ */ { - zend_function *func; - zend_class_entry *ce; + zend_string *key; + zval *zv; +#if ZEND_DEBUG + zend_bool fast_shutdown = 0; +#else + zend_bool fast_shutdown = is_zend_mm() && !EG(full_tables_cleanup); +#endif zend_try { + zend_llist_destroy(&CG(open_files)); + } zend_end_try(); -/* Removed because this can not be safely done, e.g. in this situation: - Object 1 creates object 2 - Object 3 holds reference to object 2. - Now when 1 and 2 are destroyed, 3 can still access 2 in its destructor, with - very problematic results */ -/* zend_objects_store_call_destructors(&EG(objects_store)); */ + zend_try { + zend_close_rsrc_list(&EG(regular_list)); + } zend_end_try(); -/* Moved after symbol table cleaners, because some of the cleaners can call - destructors, which would use EG(symtable_cache_ptr) and thus leave leaks */ -/* while (EG(symtable_cache_ptr)>=EG(symtable_cache)) { - zend_hash_destroy(*EG(symtable_cache_ptr)); - efree(*EG(symtable_cache_ptr)); - EG(symtable_cache_ptr)--; - } -*/ + 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. */ + EG(active) = 0; + + zend_try { zend_llist_apply(&zend_extensions, (llist_apply_func_t) zend_extension_deactivator); + } zend_end_try(); - if (CG(unclean_shutdown)) { - EG(symbol_table).pDestructor = zend_unclean_zval_ptr_dtor; - } + 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_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_cleanup_internal_classes(); + } else { zend_hash_graceful_reverse_destroy(&EG(symbol_table)); - } zend_end_try(); - EG(valid_symbol_table) = 0; - zend_try { - zval *zeh; +#if ZEND_DEBUG + if (GC_G(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) { - zeh = &EG(user_error_handler); - zval_ptr_dtor(zeh); + zval_ptr_dtor(&EG(user_error_handler)); ZVAL_UNDEF(&EG(user_error_handler)); } if (Z_TYPE(EG(user_exception_handler)) != IS_UNDEF) { - zeh = &EG(user_exception_handler); - zval_ptr_dtor(zeh); + zval_ptr_dtor(&EG(user_exception_handler)); ZVAL_UNDEF(&EG(user_exception_handler)); } zend_stack_clean(&EG(user_error_handlers_error_reporting), NULL, 1); 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); - } zend_end_try(); - zend_try { - /* Cleanup static data for functions and arrays. - * We need a separate cleanup stage because of the following problem: - * Suppose we destroy class X, which destroys the class's function table, - * and in the function table we have function foo() that has static $bar. - * Now if an object of class X is assigned to $bar, its destructor will be - * called and will fail since X's function table is in mid-destruction. - * So we want first of all to clean up all data and then move to tables destruction. - * Note that only run-time accessed data need to be cleaned up, pre-defined data can - * not contain objects and thus are not probelmatic */ + zend_vm_stack_destroy(); + if (EG(full_tables_cleanup)) { - ZEND_HASH_FOREACH_PTR(EG(function_table), func) { - if (func->type == ZEND_USER_FUNCTION) { - zend_cleanup_op_array_data((zend_op_array *) func); + zend_hash_reverse_apply(EG(zend_constants), clean_non_persistent_constant_full); + zend_hash_reverse_apply(EG(function_table), clean_non_persistent_function_full); + zend_hash_reverse_apply(EG(class_table), clean_non_persistent_class_full); + } 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) { + break; } - } ZEND_HASH_FOREACH_END(); - ZEND_HASH_REVERSE_FOREACH_PTR(EG(class_table), ce) { - if (ce->type == ZEND_USER_CLASS) { - zend_cleanup_user_class_data(ce); - } else { - zend_cleanup_internal_class_data(ce); + zval_ptr_dtor(&c->value); + if (c->name) { + zend_string_release(c->name); } - } ZEND_HASH_FOREACH_END(); - } else { - ZEND_HASH_REVERSE_FOREACH_PTR(EG(function_table), func) { - if (func->type != ZEND_USER_FUNCTION) { + efree(c); + zend_string_release(key); + } 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) { break; } - zend_cleanup_op_array_data((zend_op_array *) func); - } ZEND_HASH_FOREACH_END(); - ZEND_HASH_REVERSE_FOREACH_PTR(EG(class_table), ce) { - if (ce->type != ZEND_USER_CLASS) { + destroy_op_array(&func->op_array); + zend_string_release(key); + } 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) { break; } - zend_cleanup_user_class_data(ce); - } ZEND_HASH_FOREACH_END(); - zend_cleanup_internal_classes(); + destroy_zend_class(zv); + zend_string_release(key); + } ZEND_HASH_FOREACH_END_DEL(); } - } zend_end_try(); - zend_try { - zend_llist_destroy(&CG(open_files)); - } zend_end_try(); - - zend_try { - clean_non_persistent_constants(); - } zend_end_try(); - - zend_try { - zend_close_rsrc_list(&EG(regular_list)); - } zend_end_try(); - -#if ZEND_DEBUG - if (GC_G(gc_enabled) && !CG(unclean_shutdown)) { - gc_collect_cycles(); - } -#endif - - zend_try { - zend_objects_store_free_object_storage(&EG(objects_store)); - - zend_vm_stack_destroy(); - - /* Destroy all op arrays */ - if (EG(full_tables_cleanup)) { - zend_hash_reverse_apply(EG(function_table), clean_non_persistent_function_full); - zend_hash_reverse_apply(EG(class_table), clean_non_persistent_class_full); - } else { - zend_hash_reverse_apply(EG(function_table), clean_non_persistent_function); - zend_hash_reverse_apply(EG(class_table), clean_non_persistent_class); - } + zend_cleanup_internal_classes(); while (EG(symtable_cache_ptr)>=EG(symtable_cache)) { zend_hash_destroy(*EG(symtable_cache_ptr)); FREE_HASHTABLE(*EG(symtable_cache_ptr)); EG(symtable_cache_ptr)--; } - } zend_end_try(); - - zend_try { -#if 0&&ZEND_DEBUG - signal(SIGSEGV, original_sigsegv_handler); -#endif zend_hash_destroy(&EG(included_files)); @@ -395,9 +378,11 @@ void shutdown_executor(void) /* {{{ */ zend_hash_destroy(EG(in_autoload)); FREE_HASHTABLE(EG(in_autoload)); } - } zend_end_try(); - zend_shutdown_fpu(); + if (EG(ht_iterators) != EG(ht_iterators_slots)) { + efree(EG(ht_iterators)); + } + } #if ZEND_DEBUG if (EG(ht_iterators_used) && !CG(unclean_shutdown)) { @@ -406,11 +391,8 @@ void shutdown_executor(void) /* {{{ */ #endif EG(ht_iterators_used) = 0; - if (EG(ht_iterators) != EG(ht_iterators_slots)) { - efree(EG(ht_iterators)); - } - EG(active) = 0; + zend_shutdown_fpu(); } /* }}} */ @@ -505,7 +487,7 @@ ZEND_API zend_string *zend_get_executed_filename_ex(void) /* {{{ */ } /* }}} */ -ZEND_API uint zend_get_executed_lineno(void) /* {{{ */ +ZEND_API uint32_t zend_get_executed_lineno(void) /* {{{ */ { zend_execute_data *ex = EG(current_execute_data); @@ -573,7 +555,7 @@ ZEND_API int zval_update_constant_ex(zval *p, zend_class_entry *scope) /* {{{ */ 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_IMMUTABLE) == 0; + 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) { @@ -609,7 +591,7 @@ ZEND_API int zval_update_constant_ex(zval *p, zend_class_entry *scope) /* {{{ */ actual_len -= (actual - Z_STRVAL_P(p)); } - zend_error(E_NOTICE, "Use of undefined constant %s - assumed '%s'", actual, actual); + 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; @@ -638,7 +620,7 @@ ZEND_API int zval_update_constant_ex(zval *p, zend_class_entry *scope) /* {{{ */ } else if (Z_TYPE_P(p) == IS_CONSTANT_AST) { zval tmp; - inline_change = (Z_TYPE_FLAGS_P(p) & IS_TYPE_IMMUTABLE) == 0; + 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; } @@ -722,19 +704,18 @@ int zend_call_function(zend_fcall_info *fci, zend_fcall_info_cache *fci_cache) / } if (!fci_cache || !fci_cache->initialized) { - zend_string *callable_name; char *error = NULL; if (!fci_cache) { fci_cache = &fci_cache_local; } - if (!zend_is_callable_ex(&fci->function_name, fci->object, IS_CALLABLE_CHECK_SILENT, &callable_name, fci_cache, &error)) { + if (!zend_is_callable_ex(&fci->function_name, fci->object, IS_CALLABLE_CHECK_SILENT, NULL, fci_cache, &error)) { if (error) { + zend_string *callable_name + = 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); - } - if (callable_name) { zend_string_release(callable_name); } if (EG(current_execute_data) == &dummy_execute_data) { @@ -749,16 +730,12 @@ int zend_call_function(zend_fcall_info *fci, zend_fcall_info_cache *fci_cache) / zend_error(E_DEPRECATED, "%s", error); efree(error); if (UNEXPECTED(EG(exception))) { - if (callable_name) { - zend_string_release(callable_name); - } if (EG(current_execute_data) == &dummy_execute_data) { EG(current_execute_data) = dummy_execute_data.prev_execute_data; } return FAILURE; } } - zend_string_release(callable_name); } func = fci_cache->function_handler; @@ -767,38 +744,19 @@ int zend_call_function(zend_fcall_info *fci, zend_fcall_info_cache *fci_cache) / call = zend_vm_stack_push_call_frame(ZEND_CALL_TOP_FUNCTION | ZEND_CALL_DYNAMIC, func, fci->param_count, fci_cache->called_scope, fci->object); - if (fci->object && - (!EG(objects_store).object_buckets || - !IS_OBJ_VALID(EG(objects_store).object_buckets[fci->object->handle]))) { - 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; - } - return FAILURE; - } - if (func->common.fn_flags & (ZEND_ACC_ABSTRACT|ZEND_ACC_DEPRECATED)) { - if (func->common.fn_flags & ZEND_ACC_ABSTRACT) { - zend_throw_error(NULL, "Cannot call abstract method %s::%s()", ZSTR_VAL(func->common.scope->name), ZSTR_VAL(func->common.function_name)); + if (UNEXPECTED(func->common.fn_flags & ZEND_ACC_DEPRECATED)) { + zend_error(E_DEPRECATED, "Function %s%s%s() is deprecated", + func->common.scope ? ZSTR_VAL(func->common.scope->name) : "", + func->common.scope ? "::" : "", + ZSTR_VAL(func->common.function_name)); + if (UNEXPECTED(EG(exception))) { 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; } return FAILURE; } - if (func->common.fn_flags & ZEND_ACC_DEPRECATED) { - zend_error(E_DEPRECATED, "Function %s%s%s() is deprecated", - func->common.scope ? ZSTR_VAL(func->common.scope->name) : "", - func->common.scope ? "::" : "", - ZSTR_VAL(func->common.function_name)); - if (UNEXPECTED(EG(exception))) { - 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; - } - return FAILURE; - } - } } for (i=0; i<fci->param_count; i++) { @@ -842,16 +800,22 @@ 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)++; - ZEND_ADD_CALL_FLAG(call, ZEND_CALL_CLOSURE); + call_info = ZEND_CALL_CLOSURE; + if (func->common.fn_flags & ZEND_ACC_FAKE_CLOSURE) { + call_info |= ZEND_CALL_FAKE_CLOSURE; + } + ZEND_ADD_CALL_FLAG(call, call_info); } if (func->type == ZEND_USER_FUNCTION) { int call_via_handler = (func->common.fn_flags & ZEND_ACC_CALL_VIA_TRAMPOLINE) != 0; const zend_op *current_opline_before_exception = EG(opline_before_exception); - zend_init_execute_data(call, &func->op_array, fci->retval); + zend_init_func_execute_data(call, &func->op_array, fci->retval); zend_execute_ex(call); EG(opline_before_exception) = current_opline_before_exception; if (call_via_handler) { @@ -873,12 +837,6 @@ int zend_call_function(zend_fcall_info *fci, zend_fcall_info_cache *fci_cache) / EG(current_execute_data) = call->prev_execute_data; zend_vm_stack_free_args(call); - /* We shouldn't fix bad extensions here, - because it can break proper ones (Bug #34045) - if (!EX(function_state).function->common.return_reference) - { - INIT_PZVAL(f->retval); - }*/ if (EG(exception)) { zval_ptr_dtor(fci->retval); ZVAL_UNDEF(fci->retval); @@ -920,9 +878,15 @@ int zend_call_function(zend_fcall_info *fci, zend_fcall_info_cache *fci_cache) / EG(current_execute_data) = dummy_execute_data.prev_execute_data; } - if (EG(exception)) { - zend_throw_exception_internal(NULL); + if (UNEXPECTED(EG(exception))) { + if (UNEXPECTED(!EG(current_execute_data))) { + zend_throw_exception_internal(NULL); + } else if (EG(current_execute_data)->func && + ZEND_USER_CODE(EG(current_execute_data)->func->common.type)) { + zend_rethrow_exception(EG(current_execute_data)); + } } + return SUCCESS; } /* }}} */ @@ -970,7 +934,7 @@ ZEND_API zend_class_entry *zend_lookup_class_ex(zend_string *name, const zval *k } if (!EG(autoload_func)) { - zend_function *func = zend_hash_find_ptr(EG(function_table), CG(known_strings)[ZEND_STR_MAGIC_AUTOLOAD]); + zend_function *func = zend_hash_find_ptr(EG(function_table), ZSTR_KNOWN(ZEND_STR_MAGIC_AUTOLOAD)); if (func) { EG(autoload_func) = func; } else { @@ -983,10 +947,8 @@ ZEND_API zend_class_entry *zend_lookup_class_ex(zend_string *name, const zval *k } /* Verify class name before passing it to __autoload() */ - if (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)) { - if (!key) { - zend_string_release(lc_name); - } + 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); return NULL; } @@ -1206,7 +1168,7 @@ static void zend_timeout_handler(int dummy) /* {{{ */ if (EG(timed_out)) { /* Die on hard timeout */ const char *error_filename = NULL; - uint error_lineno = 0; + uint32_t error_lineno = 0; char log_buffer[2048]; int output_len = 0; @@ -1681,7 +1643,7 @@ 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;; + return zend_hash_update(symbol_table, name, value) ? SUCCESS : FAILURE; } } } else { @@ -1723,7 +1685,7 @@ 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;; + return zend_hash_str_update(symbol_table, name, len, value) ? SUCCESS : FAILURE; } } } else { @@ -1754,4 +1716,6 @@ ZEND_API int zend_forbid_dynamic_call(const char *func_name) /* {{{ */ * c-basic-offset: 4 * indent-tabs-mode: t * End: + * vim600: sw=4 ts=4 fdm=marker + * vim<600: sw=4 ts=4 */ |