diff options
Diffstat (limited to 'Zend/zend_execute_API.c')
-rw-r--r-- | Zend/zend_execute_API.c | 1311 |
1 files changed, 596 insertions, 715 deletions
diff --git a/Zend/zend_execute_API.c b/Zend/zend_execute_API.c index 779e6d886f..cd2cc98b42 100644 --- a/Zend/zend_execute_API.c +++ b/Zend/zend_execute_API.c @@ -2,7 +2,7 @@ +----------------------------------------------------------------------+ | Zend Engine | +----------------------------------------------------------------------+ - | Copyright (c) 1998-2013 Zend Technologies Ltd. (http://www.zend.com) | + | Copyright (c) 1998-2014 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 | @@ -26,7 +26,7 @@ #include "zend_compile.h" #include "zend_execute.h" #include "zend_API.h" -#include "zend_ptr_stack.h" +#include "zend_stack.h" #include "zend_constants.h" #include "zend_extensions.h" #include "zend_exceptions.h" @@ -39,10 +39,10 @@ #endif ZEND_API void (*zend_execute_ex)(zend_execute_data *execute_data TSRMLS_DC); -ZEND_API void (*zend_execute_internal)(zend_execute_data *execute_data_ptr, zend_fcall_info *fci, int return_value_used TSRMLS_DC); +ZEND_API void (*zend_execute_internal)(zend_execute_data *execute_data, zval *return_value TSRMLS_DC); /* true globals */ -ZEND_API const zend_fcall_info empty_fcall_info = { 0, NULL, NULL, NULL, NULL, 0, NULL, NULL, 0 }; +ZEND_API const zend_fcall_info empty_fcall_info = { 0, NULL, {{0}, {{0}}, {0}}, NULL, NULL, NULL, NULL, 0, 0 }; ZEND_API const zend_fcall_info_cache empty_fcall_info_cache = { 0, NULL, NULL, NULL, NULL }; #ifdef ZEND_WIN32 @@ -103,27 +103,31 @@ static void zend_extension_deactivator(zend_extension *extension TSRMLS_DC) /* { } /* }}} */ -static int clean_non_persistent_function(zend_function *function TSRMLS_DC) /* {{{ */ +static int clean_non_persistent_function(zval *zv TSRMLS_DC) /* {{{ */ { + zend_function *function = Z_PTR_P(zv); return (function->type == ZEND_INTERNAL_FUNCTION) ? ZEND_HASH_APPLY_STOP : ZEND_HASH_APPLY_REMOVE; } /* }}} */ -static int clean_non_persistent_function_full(zend_function *function TSRMLS_DC) /* {{{ */ +ZEND_API int clean_non_persistent_function_full(zval *zv TSRMLS_DC) /* {{{ */ { + 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(zend_class_entry **ce TSRMLS_DC) /* {{{ */ +static int clean_non_persistent_class(zval *zv TSRMLS_DC) /* {{{ */ { - return ((*ce)->type == ZEND_INTERNAL_CLASS) ? ZEND_HASH_APPLY_STOP : ZEND_HASH_APPLY_REMOVE; + zend_class_entry *ce = Z_PTR_P(zv); + return (ce->type == ZEND_INTERNAL_CLASS) ? ZEND_HASH_APPLY_STOP : ZEND_HASH_APPLY_REMOVE; } /* }}} */ -static int clean_non_persistent_class_full(zend_class_entry **ce TSRMLS_DC) /* {{{ */ +ZEND_API int clean_non_persistent_class_full(zval *zv TSRMLS_DC) /* {{{ */ { - return ((*ce)->type == ZEND_INTERNAL_CLASS) ? ZEND_HASH_APPLY_KEEP : ZEND_HASH_APPLY_REMOVE; + zend_class_entry *ce = Z_PTR_P(zv); + return (ce->type == ZEND_INTERNAL_CLASS) ? ZEND_HASH_APPLY_KEEP : ZEND_HASH_APPLY_REMOVE; } /* }}} */ @@ -131,17 +135,13 @@ void init_executor(TSRMLS_D) /* {{{ */ { zend_init_fpu(TSRMLS_C); - INIT_ZVAL(EG(uninitialized_zval)); + ZVAL_NULL(&EG(uninitialized_zval)); /* trick to make uninitialized_zval never be modified, passed by ref, etc. */ - Z_ADDREF(EG(uninitialized_zval)); - INIT_ZVAL(EG(error_zval)); - EG(uninitialized_zval_ptr)=&EG(uninitialized_zval); - EG(error_zval_ptr)=&EG(error_zval); + ZVAL_NULL(&EG(error_zval)); /* destroys stack frame, therefore makes core dumps worthless */ #if 0&&ZEND_DEBUG original_sigsegv_handler = signal(SIGSEGV, zend_handle_sigsegv); #endif - EG(return_value_ptr_ptr) = NULL; EG(symtable_cache_ptr) = EG(symtable_cache) - 1; EG(symtable_cache_limit) = EG(symtable_cache) + SYMTABLE_CACHE_SIZE - 1; @@ -150,31 +150,30 @@ void init_executor(TSRMLS_D) /* {{{ */ EG(function_table) = CG(function_table); EG(class_table) = CG(class_table); - EG(in_execution) = 0; EG(in_autoload) = NULL; EG(autoload_func) = NULL; EG(error_handling) = EH_NORMAL; zend_vm_stack_init(TSRMLS_C); - zend_vm_stack_push((void *) NULL TSRMLS_CC); - zend_hash_init(&EG(symbol_table), 50, NULL, ZVAL_PTR_DTOR, 0); - EG(active_symbol_table) = &EG(symbol_table); + zend_hash_init(&EG(symbol_table).ht, 64, NULL, ZVAL_PTR_DTOR, 0); + GC_REFCOUNT(&EG(symbol_table)) = 1; + GC_TYPE_INFO(&EG(symbol_table)) = IS_ARRAY; + EG(valid_symbol_table) = 1; zend_llist_apply(&zend_extensions, (llist_apply_func_t) zend_extension_activator TSRMLS_CC); - EG(opline_ptr) = NULL; - zend_hash_init(&EG(included_files), 5, NULL, NULL, 0); + zend_hash_init(&EG(included_files), 8, NULL, NULL, 0); EG(ticks_count) = 0; - EG(user_error_handler) = NULL; + ZVAL_UNDEF(&EG(user_error_handler)); EG(current_execute_data) = NULL; - zend_stack_init(&EG(user_error_handlers_error_reporting)); - zend_ptr_stack_init(&EG(user_error_handlers)); - zend_ptr_stack_init(&EG(user_exception_handlers)); + zend_stack_init(&EG(user_error_handlers_error_reporting), sizeof(int)); + zend_stack_init(&EG(user_error_handlers), sizeof(zval)); + zend_stack_init(&EG(user_exception_handlers), sizeof(zval)); zend_objects_store_init(&EG(objects_store), 1024); @@ -187,20 +186,17 @@ void init_executor(TSRMLS_D) /* {{{ */ EG(prev_exception) = NULL; EG(scope) = NULL; - EG(called_scope) = NULL; - - EG(This) = NULL; - - EG(active_op_array) = NULL; EG(active) = 1; - EG(start_op) = NULL; } /* }}} */ -static int zval_call_destructor(zval **zv TSRMLS_DC) /* {{{ */ +static int zval_call_destructor(zval *zv TSRMLS_DC) /* {{{ */ { - if (Z_TYPE_PP(zv) == IS_OBJECT && Z_REFCOUNT_PP(zv) == 1) { + if (Z_TYPE_P(zv) == IS_INDIRECT) { + zv = Z_INDIRECT_P(zv); + } + if (Z_TYPE_P(zv) == IS_OBJECT && Z_REFCOUNT_P(zv) == 1) { return ZEND_HASH_APPLY_REMOVE; } else { return ZEND_HASH_APPLY_KEEP; @@ -208,14 +204,28 @@ static int zval_call_destructor(zval **zv TSRMLS_DC) /* {{{ */ } /* }}} */ +static void zend_unclean_zval_ptr_dtor(zval *zv) /* {{{ */ +{ + TSRMLS_FETCH(); + + if (Z_TYPE_P(zv) == IS_INDIRECT) { + zv = Z_INDIRECT_P(zv); + } + i_zval_ptr_dtor(zv ZEND_FILE_LINE_CC TSRMLS_CC); +} +/* }}} */ + void shutdown_destructors(TSRMLS_D) /* {{{ */ { + if (CG(unclean_shutdown)) { + EG(symbol_table).ht.pDestructor = zend_unclean_zval_ptr_dtor; + } zend_try { int symbols; do { - symbols = zend_hash_num_elements(&EG(symbol_table)); - zend_hash_reverse_apply(&EG(symbol_table), (apply_func_t) zval_call_destructor TSRMLS_CC); - } while (symbols != zend_hash_num_elements(&EG(symbol_table))); + symbols = zend_hash_num_elements(&EG(symbol_table).ht); + zend_hash_reverse_apply(&EG(symbol_table).ht, (apply_func_t) zval_call_destructor TSRMLS_CC); + } while (symbols != zend_hash_num_elements(&EG(symbol_table).ht)); zend_objects_store_call_destructors(&EG(objects_store) TSRMLS_CC); } zend_catch { /* if we couldn't destruct cleanly, mark all objects as destructed anyway */ @@ -226,6 +236,9 @@ void shutdown_destructors(TSRMLS_D) /* {{{ */ void shutdown_executor(TSRMLS_D) /* {{{ */ { + zend_function *func; + zend_class_entry *ce; + zend_try { /* Removed because this can not be safely done, e.g. in this situation: @@ -244,29 +257,33 @@ void shutdown_executor(TSRMLS_D) /* {{{ */ } */ zend_llist_apply(&zend_extensions, (llist_apply_func_t) zend_extension_deactivator TSRMLS_CC); - zend_hash_graceful_reverse_destroy(&EG(symbol_table)); + + if (CG(unclean_shutdown)) { + EG(symbol_table).ht.pDestructor = zend_unclean_zval_ptr_dtor; + } + zend_hash_graceful_reverse_destroy(&EG(symbol_table).ht); } zend_end_try(); + EG(valid_symbol_table) = 0; zend_try { zval *zeh; /* remove error handlers before destroying classes and functions, * so that if handler used some class, crash would not happen */ - if (EG(user_error_handler)) { - zeh = EG(user_error_handler); - EG(user_error_handler) = NULL; - zval_ptr_dtor(&zeh); + if (Z_TYPE(EG(user_error_handler)) != IS_UNDEF) { + zeh = &EG(user_error_handler); + zval_ptr_dtor(zeh); + ZVAL_UNDEF(&EG(user_error_handler)); } - if (EG(user_exception_handler)) { - zeh = EG(user_exception_handler); - EG(user_exception_handler) = NULL; - zval_ptr_dtor(&zeh); + if (Z_TYPE(EG(user_exception_handler)) != IS_UNDEF) { + zeh = &EG(user_exception_handler); + zval_ptr_dtor(zeh); + ZVAL_UNDEF(&EG(user_exception_handler)); } - zend_stack_destroy(&EG(user_error_handlers_error_reporting)); - zend_stack_init(&EG(user_error_handlers_error_reporting)); - zend_ptr_stack_clean(&EG(user_error_handlers), ZVAL_DESTRUCTOR, 1); - zend_ptr_stack_clean(&EG(user_exception_handlers), ZVAL_DESTRUCTOR, 1); + zend_stack_clean(&EG(user_error_handlers_error_reporting), NULL, 1); + zend_stack_clean(&EG(user_error_handlers), (void (*)(void *))ZVAL_DESTRUCTOR, 1); + zend_stack_clean(&EG(user_exception_handlers), (void (*)(void *))ZVAL_DESTRUCTOR, 1); } zend_end_try(); zend_try { @@ -280,31 +297,59 @@ void shutdown_executor(TSRMLS_D) /* {{{ */ * Note that only run-time accessed data need to be cleaned up, pre-defined data can * not contain objects and thus are not probelmatic */ if (EG(full_tables_cleanup)) { - zend_hash_apply(EG(function_table), (apply_func_t) zend_cleanup_function_data_full TSRMLS_CC); - zend_hash_apply(EG(class_table), (apply_func_t) zend_cleanup_class_data TSRMLS_CC); + 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_FOREACH_END(); + ZEND_HASH_REVERSE_FOREACH_PTR(EG(class_table), ce) { + if (ce->type == ZEND_USER_CLASS) { + zend_cleanup_user_class_data(ce TSRMLS_CC); + } else { + zend_cleanup_internal_class_data(ce TSRMLS_CC); + } + } ZEND_HASH_FOREACH_END(); } else { - zend_hash_reverse_apply(EG(function_table), (apply_func_t) zend_cleanup_function_data TSRMLS_CC); - zend_hash_reverse_apply(EG(class_table), (apply_func_t) zend_cleanup_user_class_data TSRMLS_CC); + ZEND_HASH_REVERSE_FOREACH_PTR(EG(function_table), func) { + if (func->type != ZEND_USER_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) { + break; + } + zend_cleanup_user_class_data(ce TSRMLS_CC); + } ZEND_HASH_FOREACH_END(); zend_cleanup_internal_classes(TSRMLS_C); } } zend_end_try(); zend_try { + zend_llist_destroy(&CG(open_files)); + } zend_end_try(); + + zend_try { + zend_close_rsrc_list(&EG(regular_list) TSRMLS_CC); + } zend_end_try(); + + zend_try { zend_objects_store_free_object_storage(&EG(objects_store) TSRMLS_CC); zend_vm_stack_destroy(TSRMLS_C); /* Destroy all op arrays */ if (EG(full_tables_cleanup)) { - zend_hash_reverse_apply(EG(function_table), (apply_func_t) clean_non_persistent_function_full TSRMLS_CC); - zend_hash_reverse_apply(EG(class_table), (apply_func_t) clean_non_persistent_class_full TSRMLS_CC); + zend_hash_reverse_apply(EG(function_table), clean_non_persistent_function_full TSRMLS_CC); + zend_hash_reverse_apply(EG(class_table), clean_non_persistent_class_full TSRMLS_CC); } else { - zend_hash_reverse_apply(EG(function_table), (apply_func_t) clean_non_persistent_function TSRMLS_CC); - zend_hash_reverse_apply(EG(class_table), (apply_func_t) clean_non_persistent_class TSRMLS_CC); + zend_hash_reverse_apply(EG(function_table), clean_non_persistent_function TSRMLS_CC); + zend_hash_reverse_apply(EG(class_table), clean_non_persistent_class TSRMLS_CC); } while (EG(symtable_cache_ptr)>=EG(symtable_cache)) { - zend_hash_destroy(*EG(symtable_cache_ptr)); + zend_hash_destroy(&(*EG(symtable_cache_ptr))->ht); FREE_HASHTABLE(*EG(symtable_cache_ptr)); EG(symtable_cache_ptr)--; } @@ -322,8 +367,8 @@ void shutdown_executor(TSRMLS_D) /* {{{ */ zend_hash_destroy(&EG(included_files)); zend_stack_destroy(&EG(user_error_handlers_error_reporting)); - zend_ptr_stack_destroy(&EG(user_error_handlers)); - zend_ptr_stack_destroy(&EG(user_exception_handlers)); + zend_stack_destroy(&EG(user_error_handlers)); + zend_stack_destroy(&EG(user_exception_handlers)); zend_objects_store_destroy(&EG(objects_store)); if (EG(in_autoload)) { zend_hash_destroy(EG(in_autoload)); @@ -340,22 +385,26 @@ void shutdown_executor(TSRMLS_D) /* {{{ */ /* return class name and "::" or "". */ ZEND_API const char *get_active_class_name(const char **space TSRMLS_DC) /* {{{ */ { + zend_function *func; + if (!zend_is_executing(TSRMLS_C)) { if (space) { *space = ""; } return ""; } - switch (EG(current_execute_data)->function_state.function->type) { + + func = EG(current_execute_data)->func; + switch (func->type) { case ZEND_USER_FUNCTION: case ZEND_INTERNAL_FUNCTION: { - zend_class_entry *ce = EG(current_execute_data)->function_state.function->common.scope; + zend_class_entry *ce = func->common.scope; if (space) { *space = ce ? "::" : ""; } - return ce ? ce->name : ""; + return ce ? ce->name->val : ""; } default: if (space) { @@ -368,22 +417,25 @@ ZEND_API const char *get_active_class_name(const char **space TSRMLS_DC) /* {{{ ZEND_API const char *get_active_function_name(TSRMLS_D) /* {{{ */ { + zend_function *func; + if (!zend_is_executing(TSRMLS_C)) { return NULL; } - switch (EG(current_execute_data)->function_state.function->type) { + func = EG(current_execute_data)->func; + switch (func->type) { case ZEND_USER_FUNCTION: { - const char *function_name = ((zend_op_array *) EG(current_execute_data)->function_state.function)->function_name; + zend_string *function_name = func->common.function_name; if (function_name) { - return function_name; + return function_name->val; } else { return "main"; } } break; case ZEND_INTERNAL_FUNCTION: - return ((zend_internal_function *) EG(current_execute_data)->function_state.function)->function_name; + return func->common.function_name->val; break; default: return NULL; @@ -393,8 +445,13 @@ ZEND_API const char *get_active_function_name(TSRMLS_D) /* {{{ */ ZEND_API const char *zend_get_executed_filename(TSRMLS_D) /* {{{ */ { - if (EG(active_op_array)) { - return EG(active_op_array)->filename; + zend_execute_data *ex = EG(current_execute_data); + + while (ex && (!ex->func || !ZEND_USER_CODE(ex->func->type))) { + ex = ex->prev_execute_data; + } + if (ex) { + return ex->func->op_array.filename->val; } else { return "[no active file]"; } @@ -403,12 +460,17 @@ ZEND_API const char *zend_get_executed_filename(TSRMLS_D) /* {{{ */ ZEND_API uint zend_get_executed_lineno(TSRMLS_D) /* {{{ */ { - if(EG(exception) && EG(opline_ptr) && active_opline->opcode == ZEND_HANDLE_EXCEPTION && - active_opline->lineno == 0 && EG(opline_before_exception)) { - return EG(opline_before_exception)->lineno; + zend_execute_data *ex = EG(current_execute_data); + + while (ex && (!ex->func || !ZEND_USER_CODE(ex->func->type))) { + ex = ex->prev_execute_data; } - if (EG(opline_ptr)) { - return active_opline->lineno; + if (ex) { + if (EG(exception) && ex->opline->opcode == ZEND_HANDLE_EXCEPTION && + ex->opline->lineno == 0 && EG(opline_before_exception)) { + return EG(opline_before_exception)->lineno; + } + return ex->opline->lineno; } else { return 0; } @@ -417,102 +479,79 @@ ZEND_API uint zend_get_executed_lineno(TSRMLS_D) /* {{{ */ ZEND_API zend_bool zend_is_executing(TSRMLS_D) /* {{{ */ { - return EG(in_execution); + return EG(current_execute_data) != 0; } /* }}} */ -ZEND_API void _zval_ptr_dtor(zval **zval_ptr ZEND_FILE_LINE_DC) /* {{{ */ +ZEND_API void _zval_ptr_dtor(zval *zval_ptr ZEND_FILE_LINE_DC) /* {{{ */ { TSRMLS_FETCH(); - i_zval_ptr_dtor(*zval_ptr ZEND_FILE_LINE_RELAY_CC TSRMLS_CC); + i_zval_ptr_dtor(zval_ptr ZEND_FILE_LINE_RELAY_CC TSRMLS_CC); } /* }}} */ -ZEND_API void _zval_internal_ptr_dtor(zval **zval_ptr ZEND_FILE_LINE_DC) /* {{{ */ +ZEND_API void _zval_internal_ptr_dtor(zval *zval_ptr ZEND_FILE_LINE_DC) /* {{{ */ { -#if DEBUG_ZEND>=2 - printf("Reducing refcount for %x (%x): %d->%d\n", *zval_ptr, zval_ptr, Z_REFCOUNT_PP(zval_ptr), Z_REFCOUNT_PP(zval_ptr) - 1); -#endif - Z_DELREF_PP(zval_ptr); - if (Z_REFCOUNT_PP(zval_ptr) == 0) { - zval_internal_dtor(*zval_ptr); - free(*zval_ptr); - } else if (Z_REFCOUNT_PP(zval_ptr) == 1) { - Z_UNSET_ISREF_PP(zval_ptr); + 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); + } } } /* }}} */ -ZEND_API int zend_is_true(zval *op) /* {{{ */ +ZEND_API int zend_is_true(zval *op TSRMLS_DC) /* {{{ */ { - return i_zend_is_true(op); + return i_zend_is_true(op TSRMLS_CC); } /* }}} */ -#include "../TSRM/tsrm_strtok_r.h" - -#define IS_VISITED_CONSTANT IS_CONSTANT_INDEX +#define IS_VISITED_CONSTANT 0x80 #define IS_CONSTANT_VISITED(p) (Z_TYPE_P(p) & IS_VISITED_CONSTANT) -#define Z_REAL_TYPE_P(p) (Z_TYPE_P(p) & ~IS_VISITED_CONSTANT) -#define MARK_CONSTANT_VISITED(p) Z_TYPE_P(p) |= IS_VISITED_CONSTANT +#define MARK_CONSTANT_VISITED(p) Z_TYPE_INFO_P(p) |= IS_VISITED_CONSTANT -static void zval_deep_copy(zval **p) +ZEND_API int zval_update_constant_ex(zval *p, zend_bool inline_change, zend_class_entry *scope TSRMLS_DC) /* {{{ */ { - zval *value; - - ALLOC_ZVAL(value); - *value = **p; - Z_TYPE_P(value) &= ~IS_CONSTANT_INDEX; - zval_copy_ctor(value); - Z_TYPE_P(value) = Z_TYPE_PP(p); - INIT_PZVAL(value); - *p = value; -} - -ZEND_API int zval_update_constant_ex(zval **pp, void *arg, zend_class_entry *scope TSRMLS_DC) /* {{{ */ -{ - zval *p = *pp; - zend_bool inline_change = (zend_bool) (zend_uintptr_t) arg; - zval const_value; + zval *const_value; char *colon; if (IS_CONSTANT_VISITED(p)) { zend_error(E_ERROR, "Cannot declare self-referencing constant '%s'", Z_STRVAL_P(p)); - } else if ((Z_TYPE_P(p) & IS_CONSTANT_TYPE_MASK) == IS_CONSTANT) { + } else if (Z_TYPE_P(p) == IS_CONSTANT) { int refcount; - zend_uchar is_ref; - - SEPARATE_ZVAL_IF_NOT_REF(pp); - p = *pp; + SEPARATE_ZVAL_NOREF(p); MARK_CONSTANT_VISITED(p); - - refcount = Z_REFCOUNT_P(p); - is_ref = Z_ISREF_P(p); - - if (!zend_get_constant_ex(p->value.str.val, p->value.str.len, &const_value, scope, Z_REAL_TYPE_P(p) TSRMLS_CC)) { + refcount = Z_REFCOUNTED_P(p) ? Z_REFCOUNT_P(p) : 1; + const_value = zend_get_constant_ex(Z_STR_P(p), scope, Z_CONST_FLAGS_P(p) TSRMLS_CC); + if (!const_value) { char *actual = Z_STRVAL_P(p); if ((colon = (char*)zend_memrchr(Z_STRVAL_P(p), ':', Z_STRLEN_P(p)))) { + int len; + zend_error(E_ERROR, "Undefined class constant '%s'", Z_STRVAL_P(p)); - Z_STRLEN_P(p) -= ((colon - Z_STRVAL_P(p)) + 1); + len = Z_STRLEN_P(p) - ((colon - Z_STRVAL_P(p)) + 1); if (inline_change) { - colon = estrndup(colon, Z_STRLEN_P(p)); - str_efree(Z_STRVAL_P(p)); - Z_STRVAL_P(p) = colon; + zend_string *tmp = zend_string_init(colon + 1, len, 0); + zend_string_release(Z_STR_P(p)); + Z_STR_P(p) = tmp; } else { - Z_STRVAL_P(p) = colon + 1; + Z_STR_P(p) = zend_string_init(colon + 1, len, 0); } + Z_TYPE_FLAGS_P(p) = IS_TYPE_REFCOUNTED | IS_TYPE_COPYABLE; } else { - char *save = actual, *slash; + zend_string *save = Z_STR_P(p); + char *slash; int actual_len = Z_STRLEN_P(p); - if ((Z_TYPE_P(p) & IS_CONSTANT_UNQUALIFIED) && (slash = (char *)zend_memrchr(actual, '\\', actual_len))) { + if ((Z_CONST_FLAGS_P(p) & IS_CONSTANT_UNQUALIFIED) && (slash = (char *)zend_memrchr(actual, '\\', actual_len))) { actual = slash + 1; actual_len -= (actual - Z_STRVAL_P(p)); if (inline_change) { - actual = estrndup(actual, actual_len); - Z_STRVAL_P(p) = actual; - Z_STRLEN_P(p) = actual_len; + zend_string *s = zend_string_init(actual, actual_len, 0); + Z_STR_P(p) = s; + Z_TYPE_FLAGS_P(p) = IS_TYPE_REFCOUNTED | IS_TYPE_COPYABLE; } } if (actual[0] == '\\') { @@ -524,202 +563,88 @@ ZEND_API int zval_update_constant_ex(zval **pp, void *arg, zend_class_entry *sco } --actual_len; } - if ((Z_TYPE_P(p) & IS_CONSTANT_UNQUALIFIED) == 0) { - int fix_save = 0; - if (save[0] == '\\') { - save++; - fix_save = 1; - } - zend_error(E_ERROR, "Undefined constant '%s'", save); - if (fix_save) { - save--; + if ((Z_CONST_FLAGS_P(p) & IS_CONSTANT_UNQUALIFIED) == 0) { + if (save->val[0] == '\\') { + zend_error(E_ERROR, "Undefined constant '%s'", save->val + 1); + } else { + zend_error(E_ERROR, "Undefined constant '%s'", save->val); } if (inline_change) { - str_efree(save); + zend_string_release(save); } save = NULL; } - if (inline_change && save && save != actual) { - str_efree(save); - } zend_error(E_NOTICE, "Use of undefined constant %s - assumed '%s'", actual, actual); - p->type = IS_STRING; if (!inline_change) { - Z_STRVAL_P(p) = actual; - Z_STRLEN_P(p) = actual_len; - zval_copy_ctor(p); + ZVAL_STRINGL(p, actual, actual_len); + } else { + Z_TYPE_INFO_P(p) = Z_REFCOUNTED_P(p) ? + IS_STRING_EX : IS_INTERNED_STRING_EX; + if (save && save->val != actual) { + zend_string_release(save); + } } } } else { if (inline_change) { - str_efree(Z_STRVAL_P(p)); - } - *p = const_value; - } - - Z_SET_REFCOUNT_P(p, refcount); - Z_SET_ISREF_TO_P(p, is_ref); - } else if (Z_TYPE_P(p) == IS_CONSTANT_ARRAY) { - zval **element, *new_val; - char *str_index; - uint str_index_len; - ulong num_index; - int ret; - - SEPARATE_ZVAL_IF_NOT_REF(pp); - p = *pp; - Z_TYPE_P(p) = IS_ARRAY; - - if (!inline_change) { - zval *tmp; - HashTable *tmp_ht = NULL; - - ALLOC_HASHTABLE(tmp_ht); - zend_hash_init(tmp_ht, zend_hash_num_elements(Z_ARRVAL_P(p)), NULL, ZVAL_PTR_DTOR, 0); - zend_hash_copy(tmp_ht, Z_ARRVAL_P(p), (copy_ctor_func_t) zval_deep_copy, (void *) &tmp, sizeof(zval *)); - Z_ARRVAL_P(p) = tmp_ht; - } - - /* First go over the array and see if there are any constant indices */ - zend_hash_internal_pointer_reset(Z_ARRVAL_P(p)); - while (zend_hash_get_current_data(Z_ARRVAL_P(p), (void **) &element) == SUCCESS) { - if (!(Z_TYPE_PP(element) & IS_CONSTANT_INDEX)) { - zend_hash_move_forward(Z_ARRVAL_P(p)); - continue; + zend_string_release(Z_STR_P(p)); } - Z_TYPE_PP(element) &= ~IS_CONSTANT_INDEX; - if (zend_hash_get_current_key_ex(Z_ARRVAL_P(p), &str_index, &str_index_len, &num_index, 0, NULL) != HASH_KEY_IS_STRING) { - zend_hash_move_forward(Z_ARRVAL_P(p)); - continue; - } - if (!zend_get_constant_ex(str_index, str_index_len - 3, &const_value, scope, str_index[str_index_len - 2] TSRMLS_CC)) { - char *actual; - const char *save = str_index; - if ((colon = (char*)zend_memrchr(str_index, ':', str_index_len - 3))) { - zend_error(E_ERROR, "Undefined class constant '%s'", str_index); - str_index_len -= ((colon - str_index) + 1); - str_index = colon; - } else { - if (str_index[str_index_len - 2] & IS_CONSTANT_UNQUALIFIED) { - if ((actual = (char *)zend_memrchr(str_index, '\\', str_index_len - 3))) { - actual++; - str_index_len -= (actual - str_index); - str_index = actual; - } - } - if (str_index[0] == '\\') { - ++str_index; - --str_index_len; - } - if (save[0] == '\\') { - ++save; - } - if ((str_index[str_index_len - 2] & IS_CONSTANT_UNQUALIFIED) == 0) { - zend_error(E_ERROR, "Undefined constant '%s'", save); - } - zend_error(E_NOTICE, "Use of undefined constant %s - assumed '%s'", str_index, str_index); - } - ZVAL_STRINGL(&const_value, str_index, str_index_len-3, 1); + ZVAL_COPY_VALUE(p, const_value); + if (Z_OPT_CONSTANT_P(p)) { + zval_update_constant_ex(p, 1, NULL TSRMLS_CC); } + zval_opt_copy_ctor(p); + } - if (Z_REFCOUNT_PP(element) > 1) { - ALLOC_ZVAL(new_val); - *new_val = **element; - zval_copy_ctor(new_val); - Z_SET_REFCOUNT_P(new_val, 1); - Z_UNSET_ISREF_P(new_val); - - /* preserve this bit for inheritance */ - Z_TYPE_PP(element) |= IS_CONSTANT_INDEX; - zval_ptr_dtor(element); - *element = new_val; - } + if (Z_REFCOUNTED_P(p)) Z_SET_REFCOUNT_P(p, refcount); + } else if (Z_TYPE_P(p) == IS_CONSTANT_AST) { + zval tmp; + SEPARATE_ZVAL_NOREF(p); - switch (Z_TYPE(const_value)) { - case IS_STRING: - ret = zend_symtable_update_current_key(Z_ARRVAL_P(p), Z_STRVAL(const_value), Z_STRLEN(const_value) + 1, HASH_UPDATE_KEY_IF_BEFORE); - break; - case IS_BOOL: - case IS_LONG: - ret = zend_hash_update_current_key_ex(Z_ARRVAL_P(p), HASH_KEY_IS_LONG, NULL, 0, Z_LVAL(const_value), HASH_UPDATE_KEY_IF_BEFORE, NULL); - break; - case IS_DOUBLE: - ret = zend_hash_update_current_key_ex(Z_ARRVAL_P(p), HASH_KEY_IS_LONG, NULL, 0, zend_dval_to_lval(Z_DVAL(const_value)), HASH_UPDATE_KEY_IF_BEFORE, NULL); - break; - case IS_NULL: - ret = zend_hash_update_current_key_ex(Z_ARRVAL_P(p), HASH_KEY_IS_STRING, "", 1, 0, HASH_UPDATE_KEY_IF_BEFORE, NULL); - break; - default: - ret = SUCCESS; - break; - } - if (ret == SUCCESS) { - zend_hash_move_forward(Z_ARRVAL_P(p)); - } - zval_dtor(&const_value); + zend_ast_evaluate(&tmp, Z_ASTVAL_P(p), scope TSRMLS_CC); + if (inline_change) { + zend_ast_destroy_and_free(Z_ASTVAL_P(p)); + efree_size(Z_AST_P(p), sizeof(zend_ast_ref)); } - zend_hash_apply_with_argument(Z_ARRVAL_P(p), (apply_func_arg_t) zval_update_constant_inline_change, (void *) scope TSRMLS_CC); - zend_hash_internal_pointer_reset(Z_ARRVAL_P(p)); + ZVAL_COPY_VALUE(p, &tmp); } return 0; } /* }}} */ -ZEND_API int zval_update_constant_inline_change(zval **pp, void *scope TSRMLS_DC) /* {{{ */ +ZEND_API int zval_update_constant_inline_change(zval *pp, zend_class_entry *scope TSRMLS_DC) /* {{{ */ { - return zval_update_constant_ex(pp, (void*)1, scope TSRMLS_CC); + return zval_update_constant_ex(pp, 1, scope TSRMLS_CC); } /* }}} */ -ZEND_API int zval_update_constant_no_inline_change(zval **pp, void *scope TSRMLS_DC) /* {{{ */ +ZEND_API int zval_update_constant_no_inline_change(zval *pp, zend_class_entry *scope TSRMLS_DC) /* {{{ */ { - return zval_update_constant_ex(pp, (void*)0, scope TSRMLS_CC); + return zval_update_constant_ex(pp, 0, scope TSRMLS_CC); } /* }}} */ -ZEND_API int zval_update_constant(zval **pp, void *arg TSRMLS_DC) /* {{{ */ +ZEND_API int zval_update_constant(zval *pp, zend_bool inline_change TSRMLS_DC) /* {{{ */ { - return zval_update_constant_ex(pp, arg, NULL TSRMLS_CC); + return zval_update_constant_ex(pp, inline_change, NULL TSRMLS_CC); } /* }}} */ -int call_user_function(HashTable *function_table, zval **object_pp, zval *function_name, zval *retval_ptr, zend_uint param_count, zval *params[] TSRMLS_DC) /* {{{ */ +int call_user_function(HashTable *function_table, zval *object, zval *function_name, zval *retval_ptr, uint32_t param_count, zval params[] TSRMLS_DC) /* {{{ */ { - zval ***params_array; - zend_uint i; - int ex_retval; - zval *local_retval_ptr = NULL; - - if (param_count) { - params_array = (zval ***) emalloc(sizeof(zval **)*param_count); - for (i=0; i<param_count; i++) { - params_array[i] = ¶ms[i]; - } - } else { - params_array = NULL; - } - ex_retval = call_user_function_ex(function_table, object_pp, function_name, &local_retval_ptr, param_count, params_array, 1, NULL TSRMLS_CC); - if (local_retval_ptr) { - COPY_PZVAL_TO_ZVAL(*retval_ptr, local_retval_ptr); - } else { - INIT_ZVAL(*retval_ptr); - } - if (params_array) { - efree(params_array); - } - return ex_retval; + return call_user_function_ex(function_table, object, function_name, retval_ptr, param_count, params, 1, NULL TSRMLS_CC); } /* }}} */ -int call_user_function_ex(HashTable *function_table, zval **object_pp, zval *function_name, zval **retval_ptr_ptr, zend_uint param_count, zval **params[], int no_separation, HashTable *symbol_table TSRMLS_DC) /* {{{ */ +int call_user_function_ex(HashTable *function_table, zval *object, zval *function_name, zval *retval_ptr, uint32_t param_count, zval params[], int no_separation, zend_array *symbol_table TSRMLS_DC) /* {{{ */ { zend_fcall_info fci; fci.size = sizeof(fci); fci.function_table = function_table; - fci.object_ptr = object_pp ? *object_pp : NULL; - fci.function_name = function_name; - fci.retval_ptr_ptr = retval_ptr_ptr; + fci.object = object ? Z_OBJ_P(object) : NULL; + ZVAL_COPY_VALUE(&fci.function_name, function_name); + fci.retval = retval_ptr; fci.param_count = param_count; fci.params = params; fci.no_separation = (zend_bool) no_separation; @@ -731,20 +656,15 @@ int call_user_function_ex(HashTable *function_table, zval **object_pp, zval *fun int zend_call_function(zend_fcall_info *fci, zend_fcall_info_cache *fci_cache TSRMLS_DC) /* {{{ */ { - zend_uint i; - zval **original_return_value; - HashTable *calling_symbol_table; - zend_op_array *original_op_array; - zend_op **original_opline_ptr; - zend_class_entry *current_scope; - zend_class_entry *current_called_scope; + uint32_t i; zend_class_entry *calling_scope = NULL; - zend_class_entry *called_scope = NULL; - zval *current_this; - zend_execute_data execute_data; + zend_execute_data *call, dummy_execute_data; zend_fcall_info_cache fci_cache_local; + zend_function *func; + zend_class_entry *orig_scope; + zval tmp; - *fci->retval_ptr_ptr = NULL; + ZVAL_UNDEF(fci->retval); if (!EG(active)) { return FAILURE; /* executor is already inactive */ @@ -762,35 +682,46 @@ int zend_call_function(zend_fcall_info *fci, zend_fcall_info_cache *fci_cache TS break; } + orig_scope = EG(scope); + /* Initialize execute_data */ - if (EG(current_execute_data)) { - execute_data = *EG(current_execute_data); - EX(op_array) = NULL; - EX(opline) = NULL; - EX(object) = NULL; - } else { + if (!EG(current_execute_data)) { /* This only happens when we're called outside any execute()'s * It shouldn't be strictly necessary to NULL execute_data out, * but it may make bugs easier to spot */ - memset(&execute_data, 0, sizeof(zend_execute_data)); + memset(&dummy_execute_data, 0, sizeof(zend_execute_data)); + EG(current_execute_data) = &dummy_execute_data; + } else if (EG(current_execute_data)->func && + ZEND_USER_CODE(EG(current_execute_data)->func->common.type) && + EG(current_execute_data)->opline->opcode != ZEND_DO_FCALL) { + /* Insert fake frame in case of include or magic calls */ + dummy_execute_data = *EG(current_execute_data); + dummy_execute_data.prev_execute_data = EG(current_execute_data); + dummy_execute_data.call = NULL; + dummy_execute_data.opline = NULL; + dummy_execute_data.func = NULL; + EG(current_execute_data) = &dummy_execute_data; } if (!fci_cache || !fci_cache->initialized) { - char *callable_name; + 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_ptr, IS_CALLABLE_CHECK_SILENT, &callable_name, NULL, fci_cache, &error TSRMLS_CC)) { + if (!zend_is_callable_ex(&fci->function_name, fci->object, IS_CALLABLE_CHECK_SILENT, &callable_name, fci_cache, &error TSRMLS_CC)) { if (error) { - zend_error(E_WARNING, "Invalid callback %s, %s", callable_name, error); + zend_error(E_WARNING, "Invalid callback %s, %s", callable_name->val, error); efree(error); } if (callable_name) { - efree(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; } else if (error) { @@ -801,173 +732,152 @@ int zend_call_function(zend_fcall_info *fci, zend_fcall_info_cache *fci_cache TS zend_error(E_STRICT, "%s", error); efree(error); } - efree(callable_name); + zend_string_release(callable_name); } - EX(function_state).function = fci_cache->function_handler; + func = fci_cache->function_handler; + call = zend_vm_stack_push_call_frame(VM_FRAME_TOP_FUNCTION, + func, fci->param_count, fci_cache->called_scope, fci_cache->object, NULL TSRMLS_CC); calling_scope = fci_cache->calling_scope; - called_scope = fci_cache->called_scope; - fci->object_ptr = fci_cache->object_ptr; - EX(object) = fci->object_ptr; - if (fci->object_ptr && Z_TYPE_P(fci->object_ptr) == IS_OBJECT && - (!EG(objects_store).object_buckets || !EG(objects_store).object_buckets[Z_OBJ_HANDLE_P(fci->object_ptr)].valid)) { + fci->object = fci_cache->object; + if (fci->object && + (!EG(objects_store).object_buckets || + !IS_OBJ_VALID(EG(objects_store).object_buckets[fci->object->handle]))) { + if (EG(current_execute_data) == &dummy_execute_data) { + EG(current_execute_data) = dummy_execute_data.prev_execute_data; + } return FAILURE; } - if (EX(function_state).function->common.fn_flags & (ZEND_ACC_ABSTRACT|ZEND_ACC_DEPRECATED)) { - if (EX(function_state).function->common.fn_flags & ZEND_ACC_ABSTRACT) { - zend_error_noreturn(E_ERROR, "Cannot call abstract method %s::%s()", EX(function_state).function->common.scope->name, EX(function_state).function->common.function_name); + if (func->common.fn_flags & (ZEND_ACC_ABSTRACT|ZEND_ACC_DEPRECATED)) { + if (func->common.fn_flags & ZEND_ACC_ABSTRACT) { + zend_error_noreturn(E_ERROR, "Cannot call abstract method %s::%s()", func->common.scope->name->val, func->common.function_name->val); } - if (EX(function_state).function->common.fn_flags & ZEND_ACC_DEPRECATED) { + if (func->common.fn_flags & ZEND_ACC_DEPRECATED) { zend_error(E_DEPRECATED, "Function %s%s%s() is deprecated", - EX(function_state).function->common.scope ? EX(function_state).function->common.scope->name : "", - EX(function_state).function->common.scope ? "::" : "", - EX(function_state).function->common.function_name); + func->common.scope ? func->common.scope->name->val : "", + func->common.scope ? "::" : "", + func->common.function_name->val); } } - ZEND_VM_STACK_GROW_IF_NEEDED(fci->param_count + 1); - for (i=0; i<fci->param_count; i++) { zval *param; - if (ARG_SHOULD_BE_SENT_BY_REF(EX(function_state).function, i + 1)) { - if (!PZVAL_IS_REF(*fci->params[i]) && Z_REFCOUNT_PP(fci->params[i]) > 1) { - zval *new_zval; + if (ARG_SHOULD_BE_SENT_BY_REF(func, i + 1)) { + // TODO: Scalar values don't have reference counters anymore. + // They are assumed to be 1, and they may be easily passed by + // reference now. However, previously scalars with refcount==1 + // might be passed and with refcount>1 might not. We can support + // only single behavior ??? +#if 0 + if (Z_REFCOUNTED(fci->params[i]) && + // This solution breaks the following test (omit warning message) ??? + // Zend/tests/bug61273.phpt + // ext/reflection/tests/bug42976.phpt + // ext/standard/tests/general_functions/call_user_func_array_variation_001.phpt +#else + if (!Z_REFCOUNTED(fci->params[i]) || + // This solution breaks the following test (emit warning message) ??? + // ext/pdo_sqlite/tests/pdo_005.phpt +#endif + (!Z_ISREF(fci->params[i]) && Z_REFCOUNT(fci->params[i]) > 1)) { if (fci->no_separation && - !ARG_MAY_BE_SENT_BY_REF(EX(function_state).function, i + 1)) { - if (i || UNEXPECTED(ZEND_VM_STACK_ELEMETS(EG(argument_stack)) == (EG(argument_stack)->top))) { + !ARG_MAY_BE_SENT_BY_REF(func, i + 1)) { + if (i) { /* hack to clean up the stack */ - zend_vm_stack_push((void *) (zend_uintptr_t)i TSRMLS_CC); - zend_vm_stack_clear_multiple(0 TSRMLS_CC); + call->num_args = i; + zend_vm_stack_free_args(call TSRMLS_CC); } + zend_vm_stack_free_call_frame(call TSRMLS_CC); zend_error(E_WARNING, "Parameter %d to %s%s%s() expected to be a reference, value given", i+1, - EX(function_state).function->common.scope ? EX(function_state).function->common.scope->name : "", - EX(function_state).function->common.scope ? "::" : "", - EX(function_state).function->common.function_name); + func->common.scope ? func->common.scope->name->val : "", + func->common.scope ? "::" : "", + func->common.function_name->val); + if (EG(current_execute_data) == &dummy_execute_data) { + EG(current_execute_data) = dummy_execute_data.prev_execute_data; + } return FAILURE; } - ALLOC_ZVAL(new_zval); - *new_zval = **fci->params[i]; - zval_copy_ctor(new_zval); - Z_SET_REFCOUNT_P(new_zval, 1); - Z_DELREF_PP(fci->params[i]); - *fci->params[i] = new_zval; + if (Z_REFCOUNTED(fci->params[i])) { + Z_DELREF(fci->params[i]); + } + ZVAL_DUP(&tmp, &fci->params[i]); + ZVAL_NEW_REF(&fci->params[i], &tmp); + Z_ADDREF(fci->params[i]); + } else if (!Z_ISREF(fci->params[i])) { + ZVAL_NEW_REF(&fci->params[i], &fci->params[i]); + Z_ADDREF(fci->params[i]); + } else if (Z_REFCOUNTED(fci->params[i])) { + Z_ADDREF(fci->params[i]); } - Z_ADDREF_PP(fci->params[i]); - Z_SET_ISREF_PP(fci->params[i]); - param = *fci->params[i]; - } else if (PZVAL_IS_REF(*fci->params[i]) && + param = ZEND_CALL_ARG(call, i+1); + ZVAL_COPY_VALUE(param, &fci->params[i]); + } else if (Z_ISREF(fci->params[i]) && /* don't separate references for __call */ - (EX(function_state).function->common.fn_flags & ZEND_ACC_CALL_VIA_HANDLER) == 0 ) { - ALLOC_ZVAL(param); - *param = **(fci->params[i]); - INIT_PZVAL(param); - zval_copy_ctor(param); - } else if (*fci->params[i] != &EG(uninitialized_zval)) { - Z_ADDREF_PP(fci->params[i]); - param = *fci->params[i]; + (func->common.fn_flags & ZEND_ACC_CALL_VIA_HANDLER) == 0 ) { + param = ZEND_CALL_ARG(call, i+1); + ZVAL_DUP(param, Z_REFVAL(fci->params[i])); } else { - ALLOC_ZVAL(param); - *param = **(fci->params[i]); - INIT_PZVAL(param); + param = ZEND_CALL_ARG(call, i+1); + ZVAL_COPY(param, &fci->params[i]); } - zend_vm_stack_push(param TSRMLS_CC); } + call->num_args = fci->param_count; - EX(function_state).arguments = zend_vm_stack_top(TSRMLS_C); - zend_vm_stack_push((void*)(zend_uintptr_t)fci->param_count TSRMLS_CC); - - current_scope = EG(scope); EG(scope) = calling_scope; - - current_this = EG(This); - - current_called_scope = EG(called_scope); - if (called_scope) { - EG(called_scope) = called_scope; - } else if (EX(function_state).function->type != ZEND_INTERNAL_FUNCTION) { - EG(called_scope) = NULL; + if (func->common.fn_flags & ZEND_ACC_STATIC) { + fci->object = NULL; } - - if (fci->object_ptr) { - if ((EX(function_state).function->common.fn_flags & ZEND_ACC_STATIC)) { - EG(This) = NULL; - } else { - EG(This) = fci->object_ptr; - - if (!PZVAL_IS_REF(EG(This))) { - Z_ADDREF_P(EG(This)); /* For $this pointer */ - } else { - zval *this_ptr; - - ALLOC_ZVAL(this_ptr); - *this_ptr = *EG(This); - INIT_PZVAL(this_ptr); - zval_copy_ctor(this_ptr); - EG(This) = this_ptr; - } - } + if (!fci->object) { + Z_OBJ(call->This) = NULL; + Z_TYPE_INFO(call->This) = IS_UNDEF; } else { - EG(This) = NULL; + ZVAL_OBJ(&call->This, fci->object); + GC_REFCOUNT(fci->object)++; } - EX(prev_execute_data) = EG(current_execute_data); - EG(current_execute_data) = &execute_data; - - if (EX(function_state).function->type == ZEND_USER_FUNCTION) { - calling_symbol_table = EG(active_symbol_table); - EG(scope) = EX(function_state).function->common.scope; - if (fci->symbol_table) { - EG(active_symbol_table) = fci->symbol_table; + if (func->type == ZEND_USER_FUNCTION) { + EG(scope) = func->common.scope; + call->symbol_table = fci->symbol_table; + if (EXPECTED((func->op_array.fn_flags & ZEND_ACC_GENERATOR) == 0)) { + zend_init_execute_data(call, &func->op_array, fci->retval TSRMLS_CC); + zend_execute_ex(call TSRMLS_CC); } else { - EG(active_symbol_table) = NULL; + zend_generator_create_zval(call, &func->op_array, fci->retval TSRMLS_CC); } - - original_return_value = EG(return_value_ptr_ptr); - original_op_array = EG(active_op_array); - EG(return_value_ptr_ptr) = fci->retval_ptr_ptr; - EG(active_op_array) = (zend_op_array *) EX(function_state).function; - original_opline_ptr = EG(opline_ptr); - - if (EG(active_op_array)->fn_flags & ZEND_ACC_GENERATOR) { - *fci->retval_ptr_ptr = zend_generator_create_zval(EG(active_op_array) TSRMLS_CC); - } else { - zend_execute(EG(active_op_array) TSRMLS_CC); - } - - if (!fci->symbol_table && EG(active_symbol_table)) { - zend_clean_and_cache_symbol_table(EG(active_symbol_table) TSRMLS_CC); - } - EG(active_symbol_table) = calling_symbol_table; - EG(active_op_array) = original_op_array; - EG(return_value_ptr_ptr)=original_return_value; - EG(opline_ptr) = original_opline_ptr; - } else if (EX(function_state).function->type == ZEND_INTERNAL_FUNCTION) { - int call_via_handler = (EX(function_state).function->common.fn_flags & ZEND_ACC_CALL_VIA_HANDLER) != 0; - ALLOC_INIT_ZVAL(*fci->retval_ptr_ptr); - if (EX(function_state).function->common.scope) { - EG(scope) = EX(function_state).function->common.scope; + } else if (func->type == ZEND_INTERNAL_FUNCTION) { + int call_via_handler = (func->common.fn_flags & ZEND_ACC_CALL_VIA_HANDLER) != 0; + ZVAL_NULL(fci->retval); + if (func->common.scope) { + EG(scope) = func->common.scope; } + 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 */ - EX(function_state).function->internal_function.handler(fci->param_count, *fci->retval_ptr_ptr, fci->retval_ptr_ptr, fci->object_ptr, 1 TSRMLS_CC); + func->internal_function.handler(call, fci->retval TSRMLS_CC); } else { - zend_execute_internal(&execute_data, fci, 1 TSRMLS_CC); + zend_execute_internal(call, fci->retval TSRMLS_CC); } + EG(current_execute_data) = call->prev_execute_data; + zend_vm_stack_free_args(call TSRMLS_CC); + zend_vm_stack_free_call_frame(call TSRMLS_CC); + /* 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(*fci->retval_ptr_ptr); + INIT_PZVAL(f->retval); }*/ - if (EG(exception) && fci->retval_ptr_ptr) { - zval_ptr_dtor(fci->retval_ptr_ptr); - *fci->retval_ptr_ptr = NULL; + if (EG(exception)) { + zval_ptr_dtor(fci->retval); + ZVAL_UNDEF(fci->retval); } if (call_via_handler) { @@ -975,34 +885,40 @@ int zend_call_function(zend_fcall_info *fci, zend_fcall_info_cache *fci_cache TS fci_cache->initialized = 0; } } else { /* ZEND_OVERLOADED_FUNCTION */ - ALLOC_INIT_ZVAL(*fci->retval_ptr_ptr); + ZVAL_NULL(fci->retval); /* Not sure what should be done here if it's a static method */ - if (fci->object_ptr) { - Z_OBJ_HT_P(fci->object_ptr)->call_method(EX(function_state).function->common.function_name, fci->param_count, *fci->retval_ptr_ptr, fci->retval_ptr_ptr, fci->object_ptr, 1 TSRMLS_CC); + if (fci->object) { + call->prev_execute_data = EG(current_execute_data); + EG(current_execute_data) = call; + fci->object->handlers->call_method(func->common.function_name, fci->object, call, fci->retval TSRMLS_CC); + EG(current_execute_data) = call->prev_execute_data; } else { zend_error_noreturn(E_ERROR, "Cannot call overloaded function for non-object"); } - if (EX(function_state).function->type == ZEND_OVERLOADED_FUNCTION_TEMPORARY) { - efree((char*)EX(function_state).function->common.function_name); + zend_vm_stack_free_args(call TSRMLS_CC); + zend_vm_stack_free_call_frame(call TSRMLS_CC); + + if (func->type == ZEND_OVERLOADED_FUNCTION_TEMPORARY) { + zend_string_release(func->common.function_name); } - efree(EX(function_state).function); + efree(func); - if (EG(exception) && fci->retval_ptr_ptr) { - zval_ptr_dtor(fci->retval_ptr_ptr); - *fci->retval_ptr_ptr = NULL; + if (EG(exception)) { + zval_ptr_dtor(fci->retval); + ZVAL_UNDEF(fci->retval); } } - zend_vm_stack_clear_multiple(0 TSRMLS_CC); - if (EG(This)) { - zval_ptr_dtor(&EG(This)); + if (fci->object) { + OBJ_RELEASE(fci->object); + } + + EG(scope) = orig_scope; + if (EG(current_execute_data) == &dummy_execute_data) { + EG(current_execute_data) = dummy_execute_data.prev_execute_data; } - EG(called_scope) = current_called_scope; - EG(scope) = current_scope; - EG(This) = current_this; - EG(current_execute_data) = EX(prev_execute_data); if (EG(exception)) { zend_throw_exception_internal(NULL TSRMLS_CC); @@ -1011,47 +927,38 @@ int zend_call_function(zend_fcall_info *fci, zend_fcall_info_cache *fci_cache TS } /* }}} */ -ZEND_API int zend_lookup_class_ex(const char *name, int name_length, const zend_literal *key, int use_autoload, zend_class_entry ***ce TSRMLS_DC) /* {{{ */ +ZEND_API zend_class_entry *zend_lookup_class_ex(zend_string *name, const zval *key, int use_autoload TSRMLS_DC) /* {{{ */ { - zval **args[1]; - zval autoload_function; - zval *class_name_ptr; - zval *retval_ptr = NULL; - int retval, lc_length; - char *lc_name; - char *lc_free; + zend_class_entry *ce = NULL; + zval args[1]; + zval local_retval; + int retval; + zend_string *lc_name; zend_fcall_info fcall_info; zend_fcall_info_cache fcall_cache; - char dummy = 1; - ulong hash; - ALLOCA_FLAG(use_heap) if (key) { - lc_name = Z_STRVAL(key->constant); - lc_length = Z_STRLEN(key->constant) + 1; - hash = key->hash_value; + lc_name = Z_STR_P(key); } else { - if (name == NULL || !name_length) { - return FAILURE; + if (name == NULL || !name->len) { + return NULL; } - lc_free = lc_name = do_alloca(name_length + 1, use_heap); - zend_str_tolower_copy(lc_name, name, name_length); - lc_length = name_length + 1; - - if (lc_name[0] == '\\') { - lc_name += 1; - lc_length -= 1; + if (name->val[0] == '\\') { + lc_name = zend_string_alloc(name->len - 1, 0); + zend_str_tolower_copy(lc_name->val, name->val + 1, name->len - 1); + } else { + lc_name = zend_string_alloc(name->len, 0); + zend_str_tolower_copy(lc_name->val, name->val, name->len); } - - hash = zend_inline_hash_func(lc_name, lc_length); } - if (zend_hash_quick_find(EG(class_table), lc_name, lc_length, hash, (void **) ce) == SUCCESS) { + ce = zend_hash_find_ptr(EG(class_table), lc_name); + if (ce) { if (!key) { - free_alloca(lc_free, use_heap); + zend_string_free(lc_name); } - return SUCCESS; + return ce; } /* The compiler is not-reentrant. Make sure we __autoload() only during run-time @@ -1059,78 +966,92 @@ ZEND_API int zend_lookup_class_ex(const char *name, int name_length, const zend_ */ if (!use_autoload || zend_is_compiling(TSRMLS_C)) { if (!key) { - free_alloca(lc_free, use_heap); + zend_string_free(lc_name); } - return FAILURE; + return NULL; } + if (!EG(autoload_func)) { + zend_function *func = zend_hash_str_find_ptr(EG(function_table), ZEND_AUTOLOAD_FUNC_NAME, sizeof(ZEND_AUTOLOAD_FUNC_NAME) - 1); + if (func) { + EG(autoload_func) = func; + } else { + if (!key) { + zend_string_free(lc_name); + } + return NULL; + } + + } + + /* Verify class name before passing it to __autoload() */ + if (strspn(name->val, "0123456789_abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ\177\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\\") != name->len) { + if (!key) { + zend_string_free(lc_name); + } + return NULL; + } + if (EG(in_autoload) == NULL) { ALLOC_HASHTABLE(EG(in_autoload)); - zend_hash_init(EG(in_autoload), 0, NULL, NULL, 0); + zend_hash_init(EG(in_autoload), 8, NULL, NULL, 0); } - if (zend_hash_quick_add(EG(in_autoload), lc_name, lc_length, hash, (void**)&dummy, sizeof(char), NULL) == FAILURE) { + if (zend_hash_add_empty_element(EG(in_autoload), lc_name) == NULL) { if (!key) { - free_alloca(lc_free, use_heap); + zend_string_free(lc_name); } - return FAILURE; + return NULL; } - ZVAL_STRINGL(&autoload_function, ZEND_AUTOLOAD_FUNC_NAME, sizeof(ZEND_AUTOLOAD_FUNC_NAME) - 1, 0); + ZVAL_UNDEF(&local_retval); - ALLOC_ZVAL(class_name_ptr); - INIT_PZVAL(class_name_ptr); - if (name[0] == '\\') { - ZVAL_STRINGL(class_name_ptr, name+1, name_length-1, 1); + if (name->val[0] == '\\') { + ZVAL_STRINGL(&args[0], name->val + 1, name->len - 1); } else { - ZVAL_STRINGL(class_name_ptr, name, name_length, 1); + ZVAL_STR_COPY(&args[0], name); } - args[0] = &class_name_ptr; - fcall_info.size = sizeof(fcall_info); fcall_info.function_table = EG(function_table); - fcall_info.function_name = &autoload_function; + ZVAL_STR_COPY(&fcall_info.function_name, EG(autoload_func)->common.function_name); fcall_info.symbol_table = NULL; - fcall_info.retval_ptr_ptr = &retval_ptr; + fcall_info.retval = &local_retval; fcall_info.param_count = 1; fcall_info.params = args; - fcall_info.object_ptr = NULL; + fcall_info.object = NULL; fcall_info.no_separation = 1; - fcall_cache.initialized = EG(autoload_func) ? 1 : 0; + fcall_cache.initialized = 1; fcall_cache.function_handler = EG(autoload_func); fcall_cache.calling_scope = NULL; fcall_cache.called_scope = NULL; - fcall_cache.object_ptr = NULL; + fcall_cache.object = NULL; zend_exception_save(TSRMLS_C); retval = zend_call_function(&fcall_info, &fcall_cache TSRMLS_CC); zend_exception_restore(TSRMLS_C); - EG(autoload_func) = fcall_cache.function_handler; + zval_ptr_dtor(&args[0]); + zval_dtor(&fcall_info.function_name); - zval_ptr_dtor(&class_name_ptr); + zend_hash_del(EG(in_autoload), lc_name); - zend_hash_quick_del(EG(in_autoload), lc_name, lc_length, hash); - - if (retval_ptr) { - zval_ptr_dtor(&retval_ptr); - } + zval_ptr_dtor(&local_retval); if (retval == SUCCESS) { - retval = zend_hash_quick_find(EG(class_table), lc_name, lc_length, hash, (void **) ce); + ce = zend_hash_find_ptr(EG(class_table), lc_name); } if (!key) { - free_alloca(lc_free, use_heap); + zend_string_free(lc_name); } - return retval; + return ce; } /* }}} */ -ZEND_API int zend_lookup_class(const char *name, int name_length, zend_class_entry ***ce TSRMLS_DC) /* {{{ */ +ZEND_API zend_class_entry *zend_lookup_class(zend_string *name TSRMLS_DC) /* {{{ */ { - return zend_lookup_class_ex(name, name_length, NULL, 1, ce TSRMLS_CC); + return zend_lookup_class_ex(name, NULL, 1 TSRMLS_CC); } /* }}} */ @@ -1138,22 +1059,18 @@ ZEND_API int zend_eval_stringl(char *str, int str_len, zval *retval_ptr, char *s { zval pv; zend_op_array *new_op_array; - zend_op_array *original_active_op_array = EG(active_op_array); - zend_uint original_compiler_options; + uint32_t original_compiler_options; int retval; if (retval_ptr) { - Z_STRLEN(pv) = str_len + sizeof("return ;") - 1; - Z_STRVAL(pv) = emalloc(Z_STRLEN(pv) + 1); + ZVAL_NEW_STR(&pv, zend_string_alloc(str_len + sizeof("return ;")-1, 1)); 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] = ';'; Z_STRVAL(pv)[Z_STRLEN(pv)] = '\0'; } else { - Z_STRLEN(pv) = str_len; - Z_STRVAL(pv) = str; + ZVAL_STRINGL(&pv, str, str_len); } - Z_TYPE(pv) = IS_STRING; /*printf("Evaluating '%s'\n", pv.value.str.val);*/ @@ -1163,53 +1080,39 @@ ZEND_API int zend_eval_stringl(char *str, int str_len, zval *retval_ptr, char *s CG(compiler_options) = original_compiler_options; if (new_op_array) { - zval *local_retval_ptr=NULL; - zval **original_return_value_ptr_ptr = EG(return_value_ptr_ptr); - zend_op **original_opline_ptr = EG(opline_ptr); - int orig_interactive = CG(interactive); - - EG(return_value_ptr_ptr) = &local_retval_ptr; - EG(active_op_array) = new_op_array; - EG(no_extensions)=1; - if (!EG(active_symbol_table)) { - zend_rebuild_symbol_table(TSRMLS_C); - } - CG(interactive) = 0; + zval local_retval; + + EG(no_extensions)=1; zend_try { - zend_execute(new_op_array TSRMLS_CC); + ZVAL_UNDEF(&local_retval); + zend_execute(new_op_array, &local_retval TSRMLS_CC); } zend_catch { destroy_op_array(new_op_array TSRMLS_CC); - efree(new_op_array); + efree_size(new_op_array, sizeof(zend_op_array)); zend_bailout(); } zend_end_try(); - CG(interactive) = orig_interactive; - if (local_retval_ptr) { + if (Z_TYPE(local_retval) != IS_UNDEF) { if (retval_ptr) { - COPY_PZVAL_TO_ZVAL(*retval_ptr, local_retval_ptr); + ZVAL_COPY_VALUE(retval_ptr, &local_retval); } else { - zval_ptr_dtor(&local_retval_ptr); + zval_ptr_dtor(&local_retval); } } else { if (retval_ptr) { - INIT_ZVAL(*retval_ptr); + ZVAL_NULL(retval_ptr); } } EG(no_extensions)=0; - EG(opline_ptr) = original_opline_ptr; - EG(active_op_array) = original_active_op_array; destroy_op_array(new_op_array TSRMLS_CC); - efree(new_op_array); - EG(return_value_ptr_ptr) = original_return_value_ptr_ptr; + efree_size(new_op_array, sizeof(zend_op_array)); retval = SUCCESS; } else { retval = FAILURE; } - if (retval_ptr) { - zval_dtor(&pv); - } + zval_dtor(&pv); return retval; } /* }}} */ @@ -1239,79 +1142,6 @@ ZEND_API int zend_eval_string_ex(char *str, zval *retval_ptr, char *string_name, } /* }}} */ -void execute_new_code(TSRMLS_D) /* {{{ */ -{ - zend_op *opline, *end; - zend_op *ret_opline; - int orig_interactive; - - if (!(CG(active_op_array)->fn_flags & ZEND_ACC_INTERACTIVE) - || CG(context).backpatch_count>0 - || CG(active_op_array)->function_name - || CG(active_op_array)->type!=ZEND_USER_FUNCTION) { - return; - } - - ret_opline = get_next_op(CG(active_op_array) TSRMLS_CC); - ret_opline->opcode = ZEND_RETURN; - ret_opline->op1_type = IS_CONST; - ret_opline->op1.constant = zend_add_literal(CG(active_op_array), &EG(uninitialized_zval) TSRMLS_CC); - SET_UNUSED(ret_opline->op2); - - if (!EG(start_op)) { - EG(start_op) = CG(active_op_array)->opcodes; - } - - opline=EG(start_op); - end=CG(active_op_array)->opcodes+CG(active_op_array)->last; - - while (opline<end) { - if (opline->op1_type == IS_CONST) { - opline->op1.zv = &CG(active_op_array)->literals[opline->op1.constant].constant; - } - if (opline->op2_type == IS_CONST) { - opline->op2.zv = &CG(active_op_array)->literals[opline->op2.constant].constant; - } - switch (opline->opcode) { - case ZEND_GOTO: - if (Z_TYPE_P(opline->op2.zv) != IS_LONG) { - zend_resolve_goto_label(CG(active_op_array), opline, 1 TSRMLS_CC); - } - /* break omitted intentionally */ - case ZEND_JMP: - opline->op1.jmp_addr = &CG(active_op_array)->opcodes[opline->op1.opline_num]; - break; - case ZEND_JMPZ: - case ZEND_JMPNZ: - case ZEND_JMPZ_EX: - case ZEND_JMPNZ_EX: - case ZEND_JMP_SET: - case ZEND_JMP_SET_VAR: - opline->op2.jmp_addr = &CG(active_op_array)->opcodes[opline->op2.opline_num]; - break; - } - ZEND_VM_SET_OPCODE_HANDLER(opline); - opline++; - } - - zend_release_labels(1 TSRMLS_CC); - - EG(return_value_ptr_ptr) = NULL; - EG(active_op_array) = CG(active_op_array); - orig_interactive = CG(interactive); - CG(interactive) = 0; - zend_execute(CG(active_op_array) TSRMLS_CC); - CG(interactive) = orig_interactive; - - if (EG(exception)) { - zend_exception_error(EG(exception), E_ERROR TSRMLS_CC); - } - - CG(active_op_array)->last -= 1; /* get rid of that ZEND_RETURN */ - EG(start_op) = CG(active_op_array)->opcodes+CG(active_op_array)->last; -} -/* }}} */ - ZEND_API void zend_timeout(int dummy) /* {{{ */ { TSRMLS_FETCH(); @@ -1329,7 +1159,7 @@ ZEND_API void zend_timeout(int dummy) /* {{{ */ zend_on_timeout(EG(timeout_seconds) TSRMLS_CC); } - zend_error(E_ERROR, "Maximum execution time of %d second%s exceeded", EG(timeout_seconds), EG(timeout_seconds) == 1 ? "" : "s"); + zend_error(E_ERROR, "Maximum execution time of %pd second%s exceeded", EG(timeout_seconds), EG(timeout_seconds) == 1 ? "" : "s"); } /* }}} */ @@ -1446,7 +1276,7 @@ void zend_shutdown_timeout_thread(void) /* {{{ */ #define SIGPROF 27 #endif -void zend_set_timeout(long seconds, int reset_signals) /* {{{ */ +void zend_set_timeout(zend_long seconds, int reset_signals) /* {{{ */ { TSRMLS_FETCH(); @@ -1525,9 +1355,9 @@ void zend_unset_timeout(TSRMLS_D) /* {{{ */ } /* }}} */ -zend_class_entry *zend_fetch_class(const char *class_name, uint class_name_len, int fetch_type TSRMLS_DC) /* {{{ */ +zend_class_entry *zend_fetch_class(zend_string *class_name, int fetch_type TSRMLS_DC) /* {{{ */ { - zend_class_entry **pce; + zend_class_entry *ce; int use_autoload = (fetch_type & ZEND_FETCH_CLASS_NO_AUTOLOAD) == 0; int silent = (fetch_type & ZEND_FETCH_CLASS_SILENT) != 0; @@ -1549,12 +1379,12 @@ check_fetch_type: } return EG(scope)->parent; case ZEND_FETCH_CLASS_STATIC: - if (!EG(called_scope)) { + if (!EG(current_execute_data) || !EG(current_execute_data)->called_scope) { zend_error(E_ERROR, "Cannot access static:: when no class scope is active"); } - return EG(called_scope); + return EG(current_execute_data)->called_scope; case ZEND_FETCH_CLASS_AUTO: { - fetch_type = zend_get_class_fetch_type(class_name, class_name_len); + fetch_type = zend_get_class_fetch_type(class_name); if (fetch_type!=ZEND_FETCH_CLASS_DEFAULT) { goto check_fetch_type; } @@ -1562,44 +1392,44 @@ check_fetch_type: break; } - if (zend_lookup_class_ex(class_name, class_name_len, NULL, use_autoload, &pce TSRMLS_CC) == FAILURE) { + if ((ce = zend_lookup_class_ex(class_name, NULL, use_autoload TSRMLS_CC)) == NULL) { if (use_autoload) { if (!silent && !EG(exception)) { if (fetch_type == ZEND_FETCH_CLASS_INTERFACE) { - zend_error(E_ERROR, "Interface '%s' not found", class_name); + zend_error(E_ERROR, "Interface '%s' not found", class_name->val); } else if (fetch_type == ZEND_FETCH_CLASS_TRAIT) { - zend_error(E_ERROR, "Trait '%s' not found", class_name); + zend_error(E_ERROR, "Trait '%s' not found", class_name->val); } else { - zend_error(E_ERROR, "Class '%s' not found", class_name); + zend_error(E_ERROR, "Class '%s' not found", class_name->val); } } } return NULL; } - return *pce; + return ce; } /* }}} */ -zend_class_entry *zend_fetch_class_by_name(const char *class_name, uint class_name_len, const zend_literal *key, int fetch_type TSRMLS_DC) /* {{{ */ +zend_class_entry *zend_fetch_class_by_name(zend_string *class_name, const zval *key, int fetch_type TSRMLS_DC) /* {{{ */ { - zend_class_entry **pce; + zend_class_entry *ce; int use_autoload = (fetch_type & ZEND_FETCH_CLASS_NO_AUTOLOAD) == 0; - if (zend_lookup_class_ex(class_name, class_name_len, key, use_autoload, &pce TSRMLS_CC) == FAILURE) { + if ((ce = zend_lookup_class_ex(class_name, key, use_autoload TSRMLS_CC)) == NULL) { if (use_autoload) { if ((fetch_type & ZEND_FETCH_CLASS_SILENT) == 0 && !EG(exception)) { if ((fetch_type & ZEND_FETCH_CLASS_MASK) == ZEND_FETCH_CLASS_INTERFACE) { - zend_error(E_ERROR, "Interface '%s' not found", class_name); + zend_error(E_ERROR, "Interface '%s' not found", class_name->val); } else if ((fetch_type & ZEND_FETCH_CLASS_MASK) == ZEND_FETCH_CLASS_TRAIT) { - zend_error(E_ERROR, "Trait '%s' not found", class_name); + zend_error(E_ERROR, "Trait '%s' not found", class_name->val); } else { - zend_error(E_ERROR, "Class '%s' not found", class_name); + zend_error(E_ERROR, "Class '%s' not found", class_name->val); } } } return NULL; } - return *pce; + return ce; } /* }}} */ @@ -1608,7 +1438,7 @@ zend_class_entry *zend_fetch_class_by_name(const char *class_name, uint class_na #define DISPLAY_ABSTRACT_FN(idx) \ ai.afn[idx] ? ZEND_FN_SCOPE_NAME(ai.afn[idx]) : "", \ ai.afn[idx] ? "::" : "", \ - ai.afn[idx] ? ai.afn[idx]->common.function_name : "", \ + ai.afn[idx] ? ai.afn[idx]->common.function_name->val : "", \ ai.afn[idx] && ai.afn[idx + 1] ? ", " : (ai.afn[idx] && ai.cnt > MAX_ABSTRACT_INFO_CNT ? ", ..." : "") typedef struct _zend_abstract_info { @@ -1617,7 +1447,7 @@ typedef struct _zend_abstract_info { int ctor; } zend_abstract_info; -static int zend_verify_abstract_class_function(zend_function *fn, zend_abstract_info *ai TSRMLS_DC) /* {{{ */ +static void zend_verify_abstract_class_function(zend_function *fn, zend_abstract_info *ai TSRMLS_DC) /* {{{ */ { if (fn->common.fn_flags & ZEND_ACC_ABSTRACT) { if (ai->cnt < MAX_ABSTRACT_INFO_CNT) { @@ -1634,22 +1464,24 @@ static int zend_verify_abstract_class_function(zend_function *fn, zend_abstract_ ai->cnt++; } } - return 0; } /* }}} */ void zend_verify_abstract_class(zend_class_entry *ce TSRMLS_DC) /* {{{ */ { + zend_function *func; zend_abstract_info ai; if ((ce->ce_flags & ZEND_ACC_IMPLICIT_ABSTRACT_CLASS) && !(ce->ce_flags & ZEND_ACC_EXPLICIT_ABSTRACT_CLASS)) { memset(&ai, 0, sizeof(ai)); - zend_hash_apply_with_argument(&ce->function_table, (apply_func_arg_t) zend_verify_abstract_class_function, &ai TSRMLS_CC); + ZEND_HASH_FOREACH_PTR(&ce->function_table, func) { + zend_verify_abstract_class_function(func, &ai TSRMLS_CC); + } ZEND_HASH_FOREACH_END(); if (ai.cnt) { zend_error(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 ")", - ce->name, ai.cnt, + ce->name->val, ai.cnt, ai.cnt > 1 ? "s" : "", DISPLAY_ABSTRACT_FN(0), DISPLAY_ABSTRACT_FN(1), @@ -1660,122 +1492,171 @@ void zend_verify_abstract_class(zend_class_entry *ce TSRMLS_DC) /* {{{ */ } /* }}} */ -ZEND_API void zend_reset_all_cv(HashTable *symbol_table TSRMLS_DC) /* {{{ */ +ZEND_API int zend_delete_global_variable(zend_string *name TSRMLS_DC) /* {{{ */ +{ + return zend_hash_del_ind(&EG(symbol_table).ht, name); +} +/* }}} */ + +ZEND_API zend_array *zend_rebuild_symbol_table(TSRMLS_D) /* {{{ */ { - zend_execute_data *ex; int i; + zend_execute_data *ex; + zend_array *symbol_table; - for (ex = EG(current_execute_data); ex; ex = ex->prev_execute_data) { - if (ex->op_array && ex->symbol_table == symbol_table) { - for (i = 0; i < ex->op_array->last_var; i++) { - *EX_CV_NUM(ex, i) = NULL; - } - } + /* Search for last called user function */ + ex = EG(current_execute_data); + while (ex && (!ex->func || !ZEND_USER_CODE(ex->func->common.type))) { + ex = ex->prev_execute_data; } + if (!ex) { + return NULL; + } + if (ex->symbol_table) { + return ex->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)--); + } else { + symbol_table = ex->symbol_table = emalloc(sizeof(zend_array)); + GC_REFCOUNT(symbol_table) = 0; + GC_TYPE_INFO(symbol_table) = IS_ARRAY; + zend_hash_init(&symbol_table->ht, ex->func->op_array.last_var, NULL, ZVAL_PTR_DTOR, 0); + /*printf("Cache miss! Initialized %x\n", EG(active_symbol_table));*/ + } + for (i = 0; i < ex->func->op_array.last_var; i++) { + zval zv; + + ZVAL_INDIRECT(&zv, EX_VAR_NUM_2(ex, i)); + zend_hash_add_new(&symbol_table->ht, + ex->func->op_array.vars[i], &zv); + } + return symbol_table; } /* }}} */ -ZEND_API void zend_delete_variable(zend_execute_data *ex, HashTable *ht, const char *name, int name_len, ulong hash_value TSRMLS_DC) /* {{{ */ +ZEND_API void zend_attach_symbol_table(zend_execute_data *execute_data) /* {{{ */ { - if (zend_hash_quick_del(ht, name, name_len, hash_value) == SUCCESS) { - name_len--; - while (ex && ex->symbol_table == ht) { - int i; - - if (ex->op_array) { - for (i = 0; i < ex->op_array->last_var; i++) { - if (ex->op_array->vars[i].hash_value == hash_value && - ex->op_array->vars[i].name_len == name_len && - !memcmp(ex->op_array->vars[i].name, name, name_len)) { - *EX_CV_NUM(ex, i) = NULL; - break; - } + int i; + zend_op_array *op_array = &execute_data->func->op_array; + HashTable *ht = &execute_data->symbol_table->ht; + + /* copy real values from symbol table into CV slots and create + INDIRECT references to CV in symbol table */ + for (i = 0; i < op_array->last_var; i++) { + zval *zv = zend_hash_find(ht, op_array->vars[i]); + + if (zv) { + if (Z_TYPE_P(zv) == IS_INDIRECT) { + zval *val = Z_INDIRECT_P(zv); + if (Z_TYPE_P(val) == IS_UNDEF) { + ZVAL_UNDEF(EX_VAR_NUM(i)); + } else { + ZVAL_COPY_VALUE(EX_VAR_NUM(i), val); } + } else { + ZVAL_COPY_VALUE(EX_VAR_NUM(i), zv); } - ex = ex->prev_execute_data; + } else { + ZVAL_UNDEF(EX_VAR_NUM(i)); + zv = zend_hash_update(ht, op_array->vars[i], EX_VAR_NUM(i)); } + ZVAL_INDIRECT(zv, EX_VAR_NUM(i)); } } /* }}} */ -ZEND_API int zend_delete_global_variable_ex(const char *name, int name_len, ulong hash_value TSRMLS_DC) /* {{{ */ +ZEND_API void zend_detach_symbol_table(zend_execute_data *execute_data) /* {{{ */ { - zend_execute_data *ex; - - if (zend_hash_quick_exists(&EG(symbol_table), name, name_len + 1, hash_value)) { - for (ex = EG(current_execute_data); ex; ex = ex->prev_execute_data) { - if (ex->op_array && ex->symbol_table == &EG(symbol_table)) { - int i; - for (i = 0; i < ex->op_array->last_var; i++) { - if (ex->op_array->vars[i].hash_value == hash_value && - ex->op_array->vars[i].name_len == name_len && - !memcmp(ex->op_array->vars[i].name, name, name_len) - ) { - *EX_CV_NUM(ex, i) = NULL; - break; - } - } - } + int i; + zend_op_array *op_array = &execute_data->func->op_array; + HashTable *ht = &execute_data->symbol_table->ht; + + /* copy real values from CV slots into symbol table */ + for (i = 0; i < op_array->last_var; i++) { + if (Z_TYPE_P(EX_VAR_NUM(i)) == IS_UNDEF) { + zend_hash_del(ht, op_array->vars[i]); + } else { + zend_hash_update(ht, op_array->vars[i], EX_VAR_NUM(i)); + ZVAL_UNDEF(EX_VAR_NUM(i)); } - return zend_hash_quick_del(&EG(symbol_table), name, name_len + 1, hash_value); } - return FAILURE; } /* }}} */ -ZEND_API int zend_delete_global_variable(const char *name, int name_len TSRMLS_DC) /* {{{ */ +ZEND_API int zend_set_local_var(zend_string *name, zval *value, int force TSRMLS_DC) /* {{{ */ { - return zend_delete_global_variable_ex(name, name_len, zend_inline_hash_func(name, name_len + 1) TSRMLS_CC); + zend_execute_data *execute_data = EG(current_execute_data); + + while (execute_data && (!execute_data->func || !ZEND_USER_CODE(execute_data->func->common.type))) { + execute_data = execute_data->prev_execute_data; + } + + if (execute_data) { + if (!execute_data->symbol_table) { + zend_ulong h = zend_string_hash_val(name); + zend_op_array *op_array = &execute_data->func->op_array; + int i; + + for (i = 0; i < op_array->last_var; i++) { + if (op_array->vars[i]->h == h && + op_array->vars[i]->len == name->len && + memcmp(op_array->vars[i]->val, name->val, name->len) == 0) { + ZVAL_COPY_VALUE(EX_VAR_NUM(i), value); + return SUCCESS; + } + } + if (force) { + zend_array *symbol_table = zend_rebuild_symbol_table(TSRMLS_C); + if (symbol_table) { + return zend_hash_update(&symbol_table->ht, name, value) ? SUCCESS : FAILURE;; + } + } + } else { + return (zend_hash_update_ind(&execute_data->symbol_table->ht, name, value) != NULL) ? SUCCESS : FAILURE; + } + } + return FAILURE; } /* }}} */ -ZEND_API void zend_rebuild_symbol_table(TSRMLS_D) /* {{{ */ +ZEND_API int zend_set_local_var_str(const char *name, int len, zval *value, int force TSRMLS_DC) /* {{{ */ { - zend_uint i; - zend_execute_data *ex; + zend_execute_data *execute_data = EG(current_execute_data); - if (!EG(active_symbol_table)) { + while (execute_data && (!execute_data->func || !ZEND_USER_CODE(execute_data->func->common.type))) { + execute_data = execute_data->prev_execute_data; + } - /* Search for last called user function */ - ex = EG(current_execute_data); - while (ex && !ex->op_array) { - ex = ex->prev_execute_data; - } - if (ex && ex->symbol_table) { - EG(active_symbol_table) = ex->symbol_table; - return; - } + if (execute_data) { + if (!execute_data->symbol_table) { + zend_ulong h = zend_hash_func(name, len); + zend_op_array *op_array = &execute_data->func->op_array; + int i; - if (ex && ex->op_array) { - if (EG(symtable_cache_ptr)>=EG(symtable_cache)) { - /*printf("Cache hit! Reusing %x\n", symtable_cache[symtable_cache_ptr]);*/ - EG(active_symbol_table) = *(EG(symtable_cache_ptr)--); - } else { - ALLOC_HASHTABLE(EG(active_symbol_table)); - zend_hash_init(EG(active_symbol_table), ex->op_array->last_var, NULL, ZVAL_PTR_DTOR, 0); - /*printf("Cache miss! Initialized %x\n", EG(active_symbol_table));*/ + for (i = 0; i < op_array->last_var; i++) { + if (op_array->vars[i]->h == h && + op_array->vars[i]->len == len && + memcmp(op_array->vars[i]->val, name, len) == 0) { + zval_ptr_dtor(EX_VAR_NUM(i)); + ZVAL_COPY_VALUE(EX_VAR_NUM(i), value); + return SUCCESS; + } } - ex->symbol_table = EG(active_symbol_table); - - if (ex->op_array->this_var != -1 && - !*EX_CV_NUM(ex, ex->op_array->this_var) && - EG(This)) { - *EX_CV_NUM(ex, ex->op_array->this_var) = (zval**)EX_CV_NUM(ex, ex->op_array->last_var + ex->op_array->this_var); - **EX_CV_NUM(ex, ex->op_array->this_var) = EG(This); - } - for (i = 0; i < ex->op_array->last_var; i++) { - if (*EX_CV_NUM(ex, i)) { - zend_hash_quick_update(EG(active_symbol_table), - ex->op_array->vars[i].name, - ex->op_array->vars[i].name_len + 1, - ex->op_array->vars[i].hash_value, - (void**)*EX_CV_NUM(ex, i), - sizeof(zval*), - (void**)EX_CV_NUM(ex, i)); + + if (force) { + zend_array *symbol_table = zend_rebuild_symbol_table(TSRMLS_C); + if (symbol_table) { + return zend_hash_str_update(&symbol_table->ht, name, len, value) ? SUCCESS : FAILURE;; } } + } else { + return (zend_hash_str_update_ind(&execute_data->symbol_table->ht, name, len, value) != NULL) ? SUCCESS : FAILURE; } } + return FAILURE; } /* }}} */ |