From 5ea50702d9619fc0c82da80c3f5b1905f72e7ade Mon Sep 17 00:00:00 2001 From: Anthony Ferrara <ircmaxell@gmail.com> Date: Thu, 29 Aug 2013 18:11:29 -0400 Subject: [PATCH 01/20] Initial concept draft of new zend autoloader --- Zend/Makefile.am | 2 +- Zend/zend_API.c | 2 +- Zend/zend_autoload.c | 249 +++++++++++++++++++++++++ Zend/zend_autoload.h | 40 +++++ Zend/zend_builtin_functions.c | 21 ++- Zend/zend_constants.c | 4 + Zend/zend_execute.h | 3 + Zend/zend_execute_API.c | 143 ++++++++------- Zend/zend_globals.h | 6 +- Zend/zend_vm_def.h | 10 +- Zend/zend_vm_execute.h | 22 +-- configure.in | 3 +- ext/spl/php_spl.c | 330 ++++++---------------------------- 13 files changed, 478 insertions(+), 357 deletions(-) create mode 100644 Zend/zend_autoload.c create mode 100644 Zend/zend_autoload.h diff --git a/Zend/Makefile.am b/Zend/Makefile.am index 6417f3eb141ed..6fe5080d68697 100644 --- a/Zend/Makefile.am +++ b/Zend/Makefile.am @@ -18,7 +18,7 @@ libZend_la_SOURCES=\ zend_default_classes.c \ zend_iterators.c zend_interfaces.c zend_exceptions.c \ zend_strtod.c zend_closures.c zend_float.c zend_string.c zend_signal.c \ - zend_generators.c + zend_generators.c zend_autoload.c libZend_la_LDFLAGS = libZend_la_LIBADD = @ZEND_EXTRA_LIBS@ diff --git a/Zend/zend_API.c b/Zend/zend_API.c index 23ad158b17d44..c657c20b6687e 100644 --- a/Zend/zend_API.c +++ b/Zend/zend_API.c @@ -2764,7 +2764,7 @@ static int zend_is_callable_check_func(int check_flags, zval *callable, zend_fca } /* Check if function with given name exists. * This may be a compound name that includes namespace name */ - if (zend_hash_find(EG(function_table), lmname, mlen+1, (void**)&fcc->function_handler) == SUCCESS) { + if (zend_lookup_function(lmname, mlen, (void**)&fcc->function_handler) == SUCCESS) { efree(lmname); return 1; } diff --git a/Zend/zend_autoload.c b/Zend/zend_autoload.c new file mode 100644 index 0000000000000..8f3abb29c172b --- /dev/null +++ b/Zend/zend_autoload.c @@ -0,0 +1,249 @@ +/* + +----------------------------------------------------------------------+ + | Zend Engine | + +----------------------------------------------------------------------+ + | Copyright (c) 1998-2013 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 | + | available through the world-wide-web at the following url: | + | http://www.zend.com/license/2_00.txt. | + | If you did not receive a copy of the Zend license and are unable to | + | obtain it through the world-wide-web, please send a note to | + | license@zend.com so we can mail you a copy immediately. | + +----------------------------------------------------------------------+ + | Authors: Anthony Ferrara <ircmaxell@php.net> | + +----------------------------------------------------------------------+ +*/ + +/* $Id$ */ + +#include "zend.h" +#include "zend_API.h" +#include "zend_execute.h" +#include "zend_globals.h" +#include "zend_globals_macros.h" +#include "zend_autoload.h" +#include "zend_hash.h" +#include "zend_execute.h" +#include "zend_interfaces.h" +#include "zend_exceptions.h" + +static char* zend_autoload_get_name_key(zend_fcall_info *fci, int *length, zend_bool *do_free TSRMLS_DC); + +int zend_autoload_call(zval* name, long type TSRMLS_DC) +{ + zval *ztype, *retval = NULL; + char *lc_name; + int lc_length; + HashTable *symbol_table; + HashPosition function_pos; + zend_autoload_func *func_info; + char dummy = 1; + + if (Z_TYPE_P(name) != IS_STRING) { + return FAILURE; + } + + switch (type) { + case ZEND_AUTOLOAD_CLASS: + symbol_table = EG(class_table); + break; + case ZEND_AUTOLOAD_FUNCTION: + symbol_table = EG(function_table); + break; + default: + return FAILURE; + } + + lc_length = Z_STRLEN_P(name); + lc_name = zend_str_tolower_dup(Z_STRVAL_P(name), lc_length); + + if (EG(autoload_funcs) == NULL || EG(autoload_funcs)->nNumOfElements == 0) { + if (type == ZEND_AUTOLOAD_CLASS + && ( + EG(autoload_legacy) != NULL + || zend_lookup_function_ex(ZEND_AUTOLOAD_FUNC_NAME, sizeof(ZEND_AUTOLOAD_FUNC_NAME) - 1, NULL, 0, &EG(autoload_legacy) TSRMLS_CC) == SUCCESS + ) + ) { + zend_call_method_with_1_params(NULL, NULL, &EG(autoload_legacy), ZEND_AUTOLOAD_FUNC_NAME, &retval, name); + if (zend_hash_exists(symbol_table, lc_name, lc_length + 1)) { + efree(lc_name); + return SUCCESS; + } + } + efree(lc_name); + return FAILURE; + } + + if (EG(autoload_stack) == NULL) { + ALLOC_HASHTABLE(EG(autoload_stack)); + zend_hash_init(EG(autoload_stack), 0, NULL, NULL, 0); + } + + if (zend_hash_add(EG(autoload_stack), lc_name, lc_length, (void**)&dummy, sizeof(char), NULL) == FAILURE) { + efree(lc_name); + return FAILURE; + } + + MAKE_STD_ZVAL(ztype); + ZVAL_LONG(ztype, type); + + zend_hash_internal_pointer_reset_ex(EG(autoload_funcs), &function_pos); + while(zend_hash_has_more_elements_ex(EG(autoload_funcs), &function_pos) == SUCCESS) { + zend_hash_get_current_data_ex(EG(autoload_funcs), (void **) &func_info, &function_pos); + if (func_info->type & type) { + func_info->fci.retval_ptr_ptr = &retval; + zend_fcall_info_argn(&func_info->fci, 2, &name, &ztype); + zend_call_function(&func_info->fci, &func_info->fcc TSRMLS_CC); + zend_exception_save(TSRMLS_C); + if (retval) { + zval_ptr_dtor(&retval); + retval = NULL; + } + if (zend_hash_exists(symbol_table, lc_name, lc_length + 1)) { + break; + } + } + zend_hash_move_forward_ex(EG(autoload_funcs), &function_pos); + } + zend_exception_restore(TSRMLS_C); + + Z_DELREF_P(ztype); + zend_hash_del(EG(autoload_stack), lc_name, lc_length); + efree(lc_name); + return SUCCESS; +} + +#define HT_MOVE_TAIL_TO_HEAD(ht) \ + (ht)->pListTail->pListNext = (ht)->pListHead; \ + (ht)->pListHead = (ht)->pListTail; \ + (ht)->pListTail = (ht)->pListHead->pListLast; \ + (ht)->pListHead->pListNext->pListLast = (ht)->pListHead;\ + (ht)->pListTail->pListNext = NULL; \ + (ht)->pListHead->pListLast = NULL; + +static char* zend_autoload_get_name_key(zend_fcall_info *fci, int *length, zend_bool *do_free TSRMLS_DC) { + char *name; + switch (Z_TYPE_P(fci->function_name)) { + case IS_STRING: + *length = Z_STRLEN_P(fci->function_name); + return Z_STRVAL_P(fci->function_name); + break; + case IS_OBJECT: + *length = sizeof(zend_object_handle); + name = emalloc(*length + 1); + *do_free = 1; + memcpy(name, &Z_OBJ_HANDLE_P(fci->function_name), *length); + name[*length] = '\0'; + return name; + break; + default: + return 0; + } +} + +int zend_autoload_register(zend_autoload_func *func, zend_bool prepend TSRMLS_DC) +{ + char *lc_name; + zend_bool do_free = 0; + int lc_length, status = SUCCESS; + + lc_name = zend_autoload_get_name_key(&func->fci, &lc_length, &do_free); + if (lc_name == 0) { + zend_error_noreturn(E_ERROR, "Unknown Function Name Type Provided"); + } else if (do_free) { + Z_ADDREF_P(func->callable); + } + + if (!EG(autoload_funcs)) { + ALLOC_HASHTABLE(EG(autoload_funcs)); + zend_hash_init(EG(autoload_funcs), 0, NULL, NULL, 0); + } else if (zend_hash_exists(EG(autoload_funcs), lc_name, lc_length + 1)) { + if (do_free) { + efree(lc_name); + Z_DELREF_P(func->callable); + } + return FAILURE; + } + + if (zend_hash_add(EG(autoload_funcs), lc_name, lc_length + 1, (void**) func, sizeof(zend_autoload_func), NULL) == FAILURE) { + status = FAILURE; + } else if (prepend) { + HT_MOVE_TAIL_TO_HEAD(EG(autoload_funcs)); + } + if (do_free) { + efree(lc_name); + Z_DELREF_P(func->callable); + } + return status; +} + +int zend_autoload_unregister(zval *callable TSRMLS_DC) +{ + zend_fcall_info fci; + zend_fcall_info_cache fcc; + char *lc_name; + zend_bool do_free = 0; + int lc_length; + + if (zend_fcall_info_init(callable, 0, &fci, &fcc, NULL, NULL) == FAILURE) { + return FAILURE; + } + + lc_name = zend_autoload_get_name_key(&fci, &lc_length, &do_free); + if (lc_name == 0) { + return FAILURE; + } + + zend_hash_del(EG(autoload_funcs), lc_name, lc_length); + if (do_free) { + efree(lc_name); + } + + return SUCCESS; +} + +ZEND_FUNCTION(autoload_register) +{ + zval *callable; + zend_autoload_func *func; + zend_bool prepend = 0; + long type = 0; + + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_DC, "z|lb", &callable, &type, &prepend) == FAILURE) { + return; + } + + func = emalloc(sizeof(zend_autoload_func)); + + if (zend_fcall_info_init(callable, 0, &func->fci, &func->fcc, NULL, NULL) == FAILURE) { + efree(func); + zend_error_noreturn(E_ERROR, "Expecting a valid callback"); + } + + func->callable = callable; + Z_ADDREF_P(callable); + + if (!type) { + func->type = ZEND_AUTOLOAD_FUNCTION | ZEND_AUTOLOAD_CLASS; + } else { + func->type = type; + } + + if (zend_autoload_register(func, prepend TSRMLS_CC) == FAILURE) { + Z_DELREF_P(callable); + efree(func); + } +} + +ZEND_FUNCTION(autoload_unregister) +{ + zval *callable; + + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_DC, "z", &callable) == FAILURE) { + return; + } + RETVAL_BOOL(zend_autoload_unregister(callable TSRMLS_CC) == SUCCESS); +} + diff --git a/Zend/zend_autoload.h b/Zend/zend_autoload.h new file mode 100644 index 0000000000000..88f6e12fd3a20 --- /dev/null +++ b/Zend/zend_autoload.h @@ -0,0 +1,40 @@ +/* + +----------------------------------------------------------------------+ + | Zend Engine | + +----------------------------------------------------------------------+ + | Copyright (c) 1998-2013 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 | + | available through the world-wide-web at the following url: | + | http://www.zend.com/license/2_00.txt. | + | If you did not receive a copy of the Zend license and are unable to | + | obtain it through the world-wide-web, please send a note to | + | license@zend.com so we can mail you a copy immediately. | + +----------------------------------------------------------------------+ + | Authors: Anthony Ferrara <ircmaxell@php.net> | + +----------------------------------------------------------------------+ +*/ + +/* $Id$ */ +#include "zend.h" +#include "zend_API.h" + +ZEND_FUNCTION(autoload_register); +ZEND_FUNCTION(autoload_unregister); + +typedef struct { + zend_fcall_info fci; + zend_fcall_info_cache fcc; + zval *callable; + long type; +} zend_autoload_func; + +int zend_autoload_call(zval* name, long type TSRMLS_DC); +int zend_autoload_register(zend_autoload_func* func, zend_bool prepend TSRMLS_DC); +int zend_autoload_unregister(zval *callable TSRMLS_DC); + +#define ZEND_AUTOLOAD_CLASS 1 +#define ZEND_AUTOLOAD_FUNCTION 2 + + diff --git a/Zend/zend_builtin_functions.c b/Zend/zend_builtin_functions.c index 44a480f2a12f4..d6de0037bb091 100644 --- a/Zend/zend_builtin_functions.c +++ b/Zend/zend_builtin_functions.c @@ -22,6 +22,7 @@ #include "zend.h" #include "zend_API.h" #include "zend_builtin_functions.h" +#include "zend_autoload.h" #include "zend_constants.h" #include "zend_ini.h" #include "zend_exceptions.h" @@ -238,6 +239,16 @@ ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_INFO_EX(arginfo_extension_loaded, 0, 0, 1) ZEND_ARG_INFO(0, extension_name) ZEND_END_ARG_INFO() + +ZEND_BEGIN_ARG_INFO_EX(arginfo_autoload_register, 0, 0, 1) + ZEND_ARG_INFO(0, callback) + ZEND_ARG_INFO(0, type) + ZEND_ARG_INFO(0, prepend) +ZEND_END_ARG_INFO() + +ZEND_BEGIN_ARG_INFO_EX(arginfo_autoload_unregister, 0, 0, 1) + ZEND_ARG_INFO(0, callback) +ZEND_END_ARG_INFO() /* }}} */ static const zend_function_entry builtin_functions[] = { /* {{{ */ @@ -307,6 +318,8 @@ static const zend_function_entry builtin_functions[] = { /* {{{ */ ZEND_FE(gc_enabled, arginfo_zend__void) ZEND_FE(gc_enable, arginfo_zend__void) ZEND_FE(gc_disable, arginfo_zend__void) + ZEND_NS_FE("php", autoload_register, arginfo_autoload_register) + ZEND_NS_FE("php", autoload_unregister, arginfo_autoload_unregister) ZEND_FE_END }; /* }}} */ @@ -316,7 +329,6 @@ ZEND_MINIT_FUNCTION(core) { /* {{{ */ INIT_CLASS_ENTRY(class_entry, "stdClass", NULL); zend_standard_class_def = zend_register_internal_class(&class_entry TSRMLS_CC); - zend_register_default_classes(TSRMLS_C); return SUCCESS; @@ -1353,8 +1365,9 @@ ZEND_FUNCTION(function_exists) zend_function *func; char *lcname; zend_bool retval; + zend_bool autoload = 1; - if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &name, &name_len) == FAILURE) { + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|b", &name, &name_len, &autoload) == FAILURE) { return; } @@ -1367,7 +1380,7 @@ ZEND_FUNCTION(function_exists) name_len--; } - retval = (zend_hash_find(EG(function_table), name, name_len+1, (void **)&func) == SUCCESS); + retval = (zend_lookup_function_ex(name, name_len+1, NULL, (int) autoload, &func) == SUCCESS); efree(lcname); @@ -1831,7 +1844,7 @@ ZEND_FUNCTION(create_function) if (retval==SUCCESS) { zend_function new_function, *func; - if (zend_hash_find(EG(function_table), LAMBDA_TEMP_FUNCNAME, sizeof(LAMBDA_TEMP_FUNCNAME), (void **) &func)==FAILURE) { + if (zend_lookup_function_ex(LAMBDA_TEMP_FUNCNAME, sizeof(LAMBDA_TEMP_FUNCNAME), NULL, 0, &func)==FAILURE) { zend_error(E_ERROR, "Unexpected inconsistency in create_function()"); RETURN_FALSE; } diff --git a/Zend/zend_constants.c b/Zend/zend_constants.c index 594559d58bf06..7718e9de28a39 100644 --- a/Zend/zend_constants.c +++ b/Zend/zend_constants.c @@ -20,6 +20,7 @@ /* $Id$ */ #include "zend.h" +#include "zend_autoload.h" #include "zend_constants.h" #include "zend_execute.h" #include "zend_variables.h" @@ -125,6 +126,9 @@ void zend_register_standard_constants(TSRMLS_D) REGISTER_MAIN_BOOL_CONSTANT("ZEND_DEBUG_BUILD", ZEND_DEBUG, CONST_PERSISTENT | CONST_CS); } REGISTER_MAIN_NULL_CONSTANT("NULL", CONST_PERSISTENT | CONST_CT_SUBST); + + REGISTER_MAIN_LONG_CONSTANT(ZEND_NS_NAME("php", "AUTOLOAD_CLASS"), ZEND_AUTOLOAD_CLASS, CONST_CS | CONST_PERSISTENT); + REGISTER_MAIN_LONG_CONSTANT(ZEND_NS_NAME("php", "AUTOLOAD_FUNCTION"), ZEND_AUTOLOAD_FUNCTION, CONST_CS | CONST_PERSISTENT); } diff --git a/Zend/zend_execute.h b/Zend/zend_execute.h index ff0758772e48b..6e470060d5b9b 100644 --- a/Zend/zend_execute.h +++ b/Zend/zend_execute.h @@ -63,6 +63,9 @@ ZEND_API void execute_internal(zend_execute_data *execute_data_ptr, struct _zend ZEND_API int zend_is_true(zval *op); ZEND_API int zend_lookup_class(const char *name, int name_length, zend_class_entry ***ce TSRMLS_DC); 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 int zend_lookup_function(const char *name, int name_length, zend_function **fbc TSRMLS_DC); +ZEND_API int zend_lookup_function_ex(const char *name, int name_length, const zend_literal *key, int use_autoload, zend_function **fbc TSRMLS_DC); + ZEND_API int zend_eval_string(char *str, zval *retval_ptr, char *string_name TSRMLS_DC); ZEND_API int zend_eval_stringl(char *str, int str_len, zval *retval_ptr, char *string_name TSRMLS_DC); ZEND_API int zend_eval_string_ex(char *str, zval *retval_ptr, char *string_name, int handle_exceptions TSRMLS_DC); diff --git a/Zend/zend_execute_API.c b/Zend/zend_execute_API.c index 83c221798416f..80048ecb325fe 100644 --- a/Zend/zend_execute_API.c +++ b/Zend/zend_execute_API.c @@ -32,6 +32,7 @@ #include "zend_exceptions.h" #include "zend_closures.h" #include "zend_generators.h" +#include "zend_autoload.h" #include "zend_vm.h" #include "zend_float.h" #ifdef HAVE_SYS_TIME_H @@ -151,8 +152,8 @@ void init_executor(TSRMLS_D) /* {{{ */ EG(class_table) = CG(class_table); EG(in_execution) = 0; - EG(in_autoload) = NULL; - EG(autoload_func) = NULL; + EG(autoload_funcs) = NULL; + EG(autoload_stack) = NULL; EG(error_handling) = EH_NORMAL; zend_vm_stack_init(TSRMLS_C); @@ -325,9 +326,13 @@ void shutdown_executor(TSRMLS_D) /* {{{ */ zend_ptr_stack_destroy(&EG(user_error_handlers)); zend_ptr_stack_destroy(&EG(user_exception_handlers)); zend_objects_store_destroy(&EG(objects_store)); - if (EG(in_autoload)) { - zend_hash_destroy(EG(in_autoload)); - FREE_HASHTABLE(EG(in_autoload)); + if (EG(autoload_stack)) { + zend_hash_destroy(EG(autoload_stack)); + FREE_HASHTABLE(EG(autoload_stack)); + } + if (EG(autoload_funcs)) { + zend_hash_destroy(EG(autoload_funcs)); + FREE_HASHTABLE(EG(autoload_funcs)); } } zend_end_try(); @@ -1010,18 +1015,81 @@ int zend_call_function(zend_fcall_info *fci, zend_fcall_info_cache *fci_cache TS } /* }}} */ +ZEND_API int zend_lookup_function(const char *name, int name_length, zend_function **fbc TSRMLS_DC) /* {{{ */ +{ + return zend_lookup_function_ex(name, name_length, NULL, 1, fbc TSRMLS_CC); +} + +ZEND_API int zend_lookup_function_ex(const char *name, int name_length, const zend_literal *key, int use_autoload, zend_function **fbc TSRMLS_DC) +{ + char *lc_name, *lc_free; + int lc_length, retval = FAILURE; + zend_ulong hash; + ALLOCA_FLAG(use_heap) + zval *function_name_ptr; + + if (key) { + lc_name = Z_STRVAL(key->constant); + lc_length = Z_STRLEN(key->constant) + 1; + hash = key->hash_value; + } else { + if (name == NULL || !name_length) { + return FAILURE; + } + + 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; + } + + hash = zend_inline_hash_func(lc_name, lc_length); + } + if (zend_hash_quick_find(EG(function_table), lc_name, lc_length, hash, (void **) fbc) == SUCCESS) { + if (!key) { + free_alloca(lc_free, use_heap); + } + return SUCCESS; + } + + /* The compiler is not-reentrant. Make sure we __autoload_function() only during run-time + * (doesn't impact functionality of __autoload_function() + */ + if (!use_autoload || zend_is_compiling(TSRMLS_C)) { + if (!key) { + free_alloca(lc_free, use_heap); + } + return FAILURE; + } + + ALLOC_ZVAL(function_name_ptr); + INIT_PZVAL(function_name_ptr); + if (name[0] == '\\') { + ZVAL_STRINGL(function_name_ptr, name+1, name_length-1, 1); + } else { + ZVAL_STRINGL(function_name_ptr, name, name_length, 1); + } + if (zend_autoload_call(function_name_ptr, ZEND_AUTOLOAD_FUNCTION TSRMLS_CC) == SUCCESS && + zend_hash_quick_find(EG(function_table), lc_name, lc_length, hash, (void **) fbc) == SUCCESS) { + retval = SUCCESS; + } + + if (!key) { + free_alloca(lc_free, use_heap); + } + return retval; + +} + 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) /* {{{ */ { - zval **args[1]; - zval autoload_function; zval *class_name_ptr; - zval *retval_ptr = NULL; - int retval, lc_length; + int lc_length, retval = FAILURE; char *lc_name; char *lc_free; - zend_fcall_info fcall_info; - zend_fcall_info_cache fcall_cache; - char dummy = 1; ulong hash; ALLOCA_FLAG(use_heap) @@ -1063,20 +1131,6 @@ ZEND_API int zend_lookup_class_ex(const char *name, int name_length, const zend_ return FAILURE; } - if (EG(in_autoload) == NULL) { - ALLOC_HASHTABLE(EG(in_autoload)); - zend_hash_init(EG(in_autoload), 0, NULL, NULL, 0); - } - - if (zend_hash_quick_add(EG(in_autoload), lc_name, lc_length, hash, (void**)&dummy, sizeof(char), NULL) == FAILURE) { - if (!key) { - free_alloca(lc_free, use_heap); - } - return FAILURE; - } - - ZVAL_STRINGL(&autoload_function, ZEND_AUTOLOAD_FUNC_NAME, sizeof(ZEND_AUTOLOAD_FUNC_NAME) - 1, 0); - ALLOC_ZVAL(class_name_ptr); INIT_PZVAL(class_name_ptr); if (name[0] == '\\') { @@ -1084,42 +1138,11 @@ ZEND_API int zend_lookup_class_ex(const char *name, int name_length, const zend_ } else { ZVAL_STRINGL(class_name_ptr, name, name_length, 1); } - - args[0] = &class_name_ptr; - - fcall_info.size = sizeof(fcall_info); - fcall_info.function_table = EG(function_table); - fcall_info.function_name = &autoload_function; - fcall_info.symbol_table = NULL; - fcall_info.retval_ptr_ptr = &retval_ptr; - fcall_info.param_count = 1; - fcall_info.params = args; - fcall_info.object_ptr = NULL; - fcall_info.no_separation = 1; - - fcall_cache.initialized = EG(autoload_func) ? 1 : 0; - fcall_cache.function_handler = EG(autoload_func); - fcall_cache.calling_scope = NULL; - fcall_cache.called_scope = NULL; - fcall_cache.object_ptr = 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(&class_name_ptr); - - zend_hash_quick_del(EG(in_autoload), lc_name, lc_length, hash); - - if (retval_ptr) { - zval_ptr_dtor(&retval_ptr); + if (zend_autoload_call(class_name_ptr, ZEND_AUTOLOAD_CLASS TSRMLS_CC) == SUCCESS && + zend_hash_quick_find(EG(class_table), lc_name, lc_length, hash, (void **) ce) == SUCCESS) { + retval = SUCCESS; } - if (retval == SUCCESS) { - retval = zend_hash_quick_find(EG(class_table), lc_name, lc_length, hash, (void **) ce); - } if (!key) { free_alloca(lc_free, use_heap); } diff --git a/Zend/zend_globals.h b/Zend/zend_globals.h index 19c29c68f324e..ae2c719511982 100644 --- a/Zend/zend_globals.h +++ b/Zend/zend_globals.h @@ -206,8 +206,10 @@ struct _zend_executor_globals { int ticks_count; zend_bool in_execution; - HashTable *in_autoload; - zend_function *autoload_func; + HashTable *autoload_stack; + HashTable *autoload_funcs; + zend_function *autoload_legacy; + zend_bool full_tables_cleanup; /* for extended information support */ diff --git a/Zend/zend_vm_def.h b/Zend/zend_vm_def.h index 7e4f7a897d2db..52b1de40cd7e6 100644 --- a/Zend/zend_vm_def.h +++ b/Zend/zend_vm_def.h @@ -2637,7 +2637,7 @@ ZEND_VM_HANDLER(59, ZEND_INIT_FCALL_BY_NAME, ANY, CONST|TMP|VAR|CV) function_name = (zval*)(opline->op2.literal+1); if (CACHED_PTR(opline->op2.literal->cache_slot)) { call->fbc = CACHED_PTR(opline->op2.literal->cache_slot); - } else if (UNEXPECTED(zend_hash_quick_find(EG(function_table), Z_STRVAL_P(function_name), Z_STRLEN_P(function_name)+1, Z_HASH_P(function_name), (void **) &call->fbc) == FAILURE)) { + } else if (UNEXPECTED(zend_lookup_function_ex(Z_STRVAL_P(function_name), Z_STRLEN_P(function_name), (zend_literal*) function_name, 1, &call->fbc) == FAILURE)) { SAVE_OPLINE(); zend_error_noreturn(E_ERROR, "Call to undefined function %s()", Z_STRVAL_P(opline->op2.zv)); } else { @@ -2666,7 +2666,7 @@ ZEND_VM_HANDLER(59, ZEND_INIT_FCALL_BY_NAME, ANY, CONST|TMP|VAR|CV) } else { lcname = zend_str_tolower_dup(function_name_strval, function_name_strlen); } - if (UNEXPECTED(zend_hash_find(EG(function_table), lcname, function_name_strlen+1, (void **) &call->fbc) == FAILURE)) { + if (UNEXPECTED(zend_lookup_function(lcname, function_name_strlen, &call->fbc) == FAILURE)) { zend_error_noreturn(E_ERROR, "Call to undefined function %s()", function_name_strval); } efree(lcname); @@ -2783,9 +2783,9 @@ ZEND_VM_HANDLER(69, ZEND_INIT_NS_FCALL_BY_NAME, ANY, CONST) func_name = opline->op2.literal + 1; if (CACHED_PTR(opline->op2.literal->cache_slot)) { call->fbc = CACHED_PTR(opline->op2.literal->cache_slot); - } else if (zend_hash_quick_find(EG(function_table), Z_STRVAL(func_name->constant), Z_STRLEN(func_name->constant)+1, func_name->hash_value, (void **) &call->fbc)==FAILURE) { + } else if (zend_lookup_function_ex(Z_STRVAL(func_name->constant), Z_STRLEN(func_name->constant), func_name->hash_value, 1, &call->fbc)==FAILURE) { func_name++; - if (UNEXPECTED(zend_hash_quick_find(EG(function_table), Z_STRVAL(func_name->constant), Z_STRLEN(func_name->constant)+1, func_name->hash_value, (void **) &call->fbc)==FAILURE)) { + if (UNEXPECTED(zend_lookup_function_ex(Z_STRVAL(func_name->constant), Z_STRLEN(func_name->constant), func_name->hash_value, 1, &call->fbc)==FAILURE)) { SAVE_OPLINE(); zend_error_noreturn(E_ERROR, "Call to undefined function %s()", Z_STRVAL_P(opline->op2.zv)); } else { @@ -2817,7 +2817,7 @@ ZEND_VM_HANDLER(60, ZEND_DO_FCALL, CONST, ANY) if (CACHED_PTR(opline->op1.literal->cache_slot)) { EX(function_state).function = CACHED_PTR(opline->op1.literal->cache_slot); - } else if (UNEXPECTED(zend_hash_quick_find(EG(function_table), Z_STRVAL_P(fname), Z_STRLEN_P(fname)+1, Z_HASH_P(fname), (void **) &EX(function_state).function)==FAILURE)) { + } else if (UNEXPECTED(zend_lookup_function_ex(Z_STRVAL_P(fname), Z_STRLEN_P(fname), (zend_literal*) fname, 1, &EX(function_state).function)==FAILURE)) { SAVE_OPLINE(); zend_error_noreturn(E_ERROR, "Call to undefined function %s()", fname->value.str.val); } else { diff --git a/Zend/zend_vm_execute.h b/Zend/zend_vm_execute.h index 9622fee5e4efa..4f13d7f1aa542 100644 --- a/Zend/zend_vm_execute.h +++ b/Zend/zend_vm_execute.h @@ -1220,7 +1220,7 @@ static int ZEND_FASTCALL ZEND_INIT_FCALL_BY_NAME_SPEC_CONST_HANDLER(ZEND_OPCODE function_name = (zval*)(opline->op2.literal+1); if (CACHED_PTR(opline->op2.literal->cache_slot)) { call->fbc = CACHED_PTR(opline->op2.literal->cache_slot); - } else if (UNEXPECTED(zend_hash_quick_find(EG(function_table), Z_STRVAL_P(function_name), Z_STRLEN_P(function_name)+1, Z_HASH_P(function_name), (void **) &call->fbc) == FAILURE)) { + } else if (UNEXPECTED(zend_lookup_function_ex(Z_STRVAL_P(function_name), Z_STRLEN_P(function_name), (zend_literal*) function_name, 1, &call->fbc) == FAILURE)) { SAVE_OPLINE(); zend_error_noreturn(E_ERROR, "Call to undefined function %s()", Z_STRVAL_P(opline->op2.zv)); } else { @@ -1249,7 +1249,7 @@ static int ZEND_FASTCALL ZEND_INIT_FCALL_BY_NAME_SPEC_CONST_HANDLER(ZEND_OPCODE } else { lcname = zend_str_tolower_dup(function_name_strval, function_name_strlen); } - if (UNEXPECTED(zend_hash_find(EG(function_table), lcname, function_name_strlen+1, (void **) &call->fbc) == FAILURE)) { + if (UNEXPECTED(zend_lookup_function(lcname, function_name_strlen, &call->fbc) == FAILURE)) { zend_error_noreturn(E_ERROR, "Call to undefined function %s()", function_name_strval); } efree(lcname); @@ -1366,9 +1366,9 @@ static int ZEND_FASTCALL ZEND_INIT_NS_FCALL_BY_NAME_SPEC_CONST_HANDLER(ZEND_OPC func_name = opline->op2.literal + 1; if (CACHED_PTR(opline->op2.literal->cache_slot)) { call->fbc = CACHED_PTR(opline->op2.literal->cache_slot); - } else if (zend_hash_quick_find(EG(function_table), Z_STRVAL(func_name->constant), Z_STRLEN(func_name->constant)+1, func_name->hash_value, (void **) &call->fbc)==FAILURE) { + } else if (zend_lookup_function_ex(Z_STRVAL(func_name->constant), Z_STRLEN(func_name->constant), func_name->hash_value, 1, &call->fbc)==FAILURE) { func_name++; - if (UNEXPECTED(zend_hash_quick_find(EG(function_table), Z_STRVAL(func_name->constant), Z_STRLEN(func_name->constant)+1, func_name->hash_value, (void **) &call->fbc)==FAILURE)) { + if (UNEXPECTED(zend_lookup_function_ex(Z_STRVAL(func_name->constant), Z_STRLEN(func_name->constant), func_name->hash_value, 1, &call->fbc)==FAILURE)) { SAVE_OPLINE(); zend_error_noreturn(E_ERROR, "Call to undefined function %s()", Z_STRVAL_P(opline->op2.zv)); } else { @@ -1545,7 +1545,7 @@ static int ZEND_FASTCALL ZEND_INIT_FCALL_BY_NAME_SPEC_TMP_HANDLER(ZEND_OPCODE_H function_name = (zval*)(opline->op2.literal+1); if (CACHED_PTR(opline->op2.literal->cache_slot)) { call->fbc = CACHED_PTR(opline->op2.literal->cache_slot); - } else if (UNEXPECTED(zend_hash_quick_find(EG(function_table), Z_STRVAL_P(function_name), Z_STRLEN_P(function_name)+1, Z_HASH_P(function_name), (void **) &call->fbc) == FAILURE)) { + } else if (UNEXPECTED(zend_lookup_function_ex(Z_STRVAL_P(function_name), Z_STRLEN_P(function_name), (zend_literal*) function_name, 1, &call->fbc) == FAILURE)) { SAVE_OPLINE(); zend_error_noreturn(E_ERROR, "Call to undefined function %s()", Z_STRVAL_P(opline->op2.zv)); } else { @@ -1574,7 +1574,7 @@ static int ZEND_FASTCALL ZEND_INIT_FCALL_BY_NAME_SPEC_TMP_HANDLER(ZEND_OPCODE_H } else { lcname = zend_str_tolower_dup(function_name_strval, function_name_strlen); } - if (UNEXPECTED(zend_hash_find(EG(function_table), lcname, function_name_strlen+1, (void **) &call->fbc) == FAILURE)) { + if (UNEXPECTED(zend_lookup_function(lcname, function_name_strlen, &call->fbc) == FAILURE)) { zend_error_noreturn(E_ERROR, "Call to undefined function %s()", function_name_strval); } efree(lcname); @@ -1732,7 +1732,7 @@ static int ZEND_FASTCALL ZEND_INIT_FCALL_BY_NAME_SPEC_VAR_HANDLER(ZEND_OPCODE_H function_name = (zval*)(opline->op2.literal+1); if (CACHED_PTR(opline->op2.literal->cache_slot)) { call->fbc = CACHED_PTR(opline->op2.literal->cache_slot); - } else if (UNEXPECTED(zend_hash_quick_find(EG(function_table), Z_STRVAL_P(function_name), Z_STRLEN_P(function_name)+1, Z_HASH_P(function_name), (void **) &call->fbc) == FAILURE)) { + } else if (UNEXPECTED(zend_lookup_function_ex(Z_STRVAL_P(function_name), Z_STRLEN_P(function_name), (zend_literal*) function_name, 1, &call->fbc) == FAILURE)) { SAVE_OPLINE(); zend_error_noreturn(E_ERROR, "Call to undefined function %s()", Z_STRVAL_P(opline->op2.zv)); } else { @@ -1761,7 +1761,7 @@ static int ZEND_FASTCALL ZEND_INIT_FCALL_BY_NAME_SPEC_VAR_HANDLER(ZEND_OPCODE_H } else { lcname = zend_str_tolower_dup(function_name_strval, function_name_strlen); } - if (UNEXPECTED(zend_hash_find(EG(function_table), lcname, function_name_strlen+1, (void **) &call->fbc) == FAILURE)) { + if (UNEXPECTED(zend_lookup_function(lcname, function_name_strlen, &call->fbc) == FAILURE)) { zend_error_noreturn(E_ERROR, "Call to undefined function %s()", function_name_strval); } efree(lcname); @@ -1957,7 +1957,7 @@ static int ZEND_FASTCALL ZEND_INIT_FCALL_BY_NAME_SPEC_CV_HANDLER(ZEND_OPCODE_HA function_name = (zval*)(opline->op2.literal+1); if (CACHED_PTR(opline->op2.literal->cache_slot)) { call->fbc = CACHED_PTR(opline->op2.literal->cache_slot); - } else if (UNEXPECTED(zend_hash_quick_find(EG(function_table), Z_STRVAL_P(function_name), Z_STRLEN_P(function_name)+1, Z_HASH_P(function_name), (void **) &call->fbc) == FAILURE)) { + } else if (UNEXPECTED(zend_lookup_function_ex(Z_STRVAL_P(function_name), Z_STRLEN_P(function_name), (zend_literal*) function_name, 1, &call->fbc) == FAILURE)) { SAVE_OPLINE(); zend_error_noreturn(E_ERROR, "Call to undefined function %s()", Z_STRVAL_P(opline->op2.zv)); } else { @@ -1986,7 +1986,7 @@ static int ZEND_FASTCALL ZEND_INIT_FCALL_BY_NAME_SPEC_CV_HANDLER(ZEND_OPCODE_HA } else { lcname = zend_str_tolower_dup(function_name_strval, function_name_strlen); } - if (UNEXPECTED(zend_hash_find(EG(function_table), lcname, function_name_strlen+1, (void **) &call->fbc) == FAILURE)) { + if (UNEXPECTED(zend_lookup_function(lcname, function_name_strlen, &call->fbc) == FAILURE)) { zend_error_noreturn(E_ERROR, "Call to undefined function %s()", function_name_strval); } efree(lcname); @@ -2311,7 +2311,7 @@ static int ZEND_FASTCALL ZEND_DO_FCALL_SPEC_CONST_HANDLER(ZEND_OPCODE_HANDLER_A if (CACHED_PTR(opline->op1.literal->cache_slot)) { EX(function_state).function = CACHED_PTR(opline->op1.literal->cache_slot); - } else if (UNEXPECTED(zend_hash_quick_find(EG(function_table), Z_STRVAL_P(fname), Z_STRLEN_P(fname)+1, Z_HASH_P(fname), (void **) &EX(function_state).function)==FAILURE)) { + } else if (UNEXPECTED(zend_lookup_function_ex(Z_STRVAL_P(fname), Z_STRLEN_P(fname), (zend_literal*) fname, 1, &EX(function_state).function)==FAILURE)) { SAVE_OPLINE(); zend_error_noreturn(E_ERROR, "Call to undefined function %s()", fname->value.str.val); } else { diff --git a/configure.in b/configure.in index 16738fe30ab67..f346bd111339d 100644 --- a/configure.in +++ b/configure.in @@ -1475,7 +1475,8 @@ PHP_ADD_SOURCES(Zend, \ zend_list.c zend_indent.c zend_builtin_functions.c zend_sprintf.c \ zend_ini.c zend_qsort.c zend_multibyte.c zend_ts_hash.c zend_stream.c \ zend_iterators.c zend_interfaces.c zend_exceptions.c zend_strtod.c zend_gc.c \ - zend_closures.c zend_float.c zend_string.c zend_signal.c zend_generators.c) + zend_closures.c zend_float.c zend_string.c zend_signal.c zend_generators.c\ + zend_autoload.c) if test -r "$abs_srcdir/Zend/zend_objects.c"; then PHP_ADD_SOURCES(Zend, zend_objects.c zend_object_handlers.c zend_objects_API.c zend_default_classes.c) diff --git a/ext/spl/php_spl.c b/ext/spl/php_spl.c index 716990d80f02a..8ce82168297d8 100644 --- a/ext/spl/php_spl.c +++ b/ext/spl/php_spl.c @@ -39,6 +39,7 @@ #include "spl_heap.h" #include "zend_exceptions.h" #include "zend_interfaces.h" +#include "zend_autoload.h" #include "ext/standard/php_rand.h" #include "ext/standard/php_lcg.h" #include "main/snprintf.h" @@ -391,65 +392,20 @@ PHP_FUNCTION(spl_autoload_extensions) } } /* }}} */ -typedef struct { - zend_function *func_ptr; - zval *obj; - zval *closure; - zend_class_entry *ce; -} autoload_func_info; - -static void autoload_func_info_dtor(autoload_func_info *alfi) -{ - if (alfi->obj) { - zval_ptr_dtor(&alfi->obj); - } - if (alfi->closure) { - zval_ptr_dtor(&alfi->closure); - } -} - /* {{{ proto void spl_autoload_call(string class_name) Try all registerd autoload function to load the requested class */ PHP_FUNCTION(spl_autoload_call) { - zval *class_name, *retval = NULL; - int class_name_len; - char *func_name, *lc_name; - uint func_name_len; - ulong dummy; - HashPosition function_pos; - autoload_func_info *alfi; + zval *class_name; if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z", &class_name) == FAILURE || Z_TYPE_P(class_name) != IS_STRING) { return; } - if (SPL_G(autoload_functions)) { - int l_autoload_running = SPL_G(autoload_running); - SPL_G(autoload_running) = 1; - class_name_len = Z_STRLEN_P(class_name); - lc_name = zend_str_tolower_dup(Z_STRVAL_P(class_name), class_name_len); - zend_hash_internal_pointer_reset_ex(SPL_G(autoload_functions), &function_pos); - while(zend_hash_has_more_elements_ex(SPL_G(autoload_functions), &function_pos) == SUCCESS) { - zend_hash_get_current_key_ex(SPL_G(autoload_functions), &func_name, &func_name_len, &dummy, 0, &function_pos); - zend_hash_get_current_data_ex(SPL_G(autoload_functions), (void **) &alfi, &function_pos); - zend_call_method(alfi->obj ? &alfi->obj : NULL, alfi->ce, &alfi->func_ptr, func_name, func_name_len, &retval, 1, class_name, NULL TSRMLS_CC); - zend_exception_save(TSRMLS_C); - if (retval) { - zval_ptr_dtor(&retval); - retval = NULL; - } - if (zend_hash_exists(EG(class_table), lc_name, class_name_len + 1)) { - break; - } - zend_hash_move_forward_ex(SPL_G(autoload_functions), &function_pos); - } - zend_exception_restore(TSRMLS_C); - efree(lc_name); - SPL_G(autoload_running) = l_autoload_running; - } else { - /* do not use or overwrite &EG(autoload_func) here */ + if (EG(autoload_funcs) == NULL) { zend_call_method_with_1_params(NULL, NULL, NULL, "spl_autoload", NULL, class_name); + } else { + zend_autoload_call(class_name, ZEND_AUTOLOAD_CLASS); } } /* }}} */ @@ -465,159 +421,78 @@ PHP_FUNCTION(spl_autoload_call) Register given function as __autoload() implementation */ PHP_FUNCTION(spl_autoload_register) { - char *func_name, *error = NULL; - int func_name_len; - char *lc_name = NULL; + char *error = NULL; zval *zcallable = NULL; zend_bool do_throw = 1; zend_bool prepend = 0; - zend_function *spl_func_ptr; - autoload_func_info alfi; - zval *obj_ptr; - zend_fcall_info_cache fcc; + zend_autoload_func *func; if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, ZEND_NUM_ARGS() TSRMLS_CC, "|zbb", &zcallable, &do_throw, &prepend) == FAILURE) { return; } - if (ZEND_NUM_ARGS()) { - if (Z_TYPE_P(zcallable) == IS_STRING) { - if (Z_STRLEN_P(zcallable) == sizeof("spl_autoload_call") - 1) { - if (!zend_binary_strcasecmp(Z_STRVAL_P(zcallable), sizeof("spl_autoload_call"), "spl_autoload_call", sizeof("spl_autoload_call"))) { - if (do_throw) { - zend_throw_exception_ex(spl_ce_LogicException, 0 TSRMLS_CC, "Function spl_autoload_call() cannot be registered"); - } - RETURN_FALSE; - } - } - } - - if (!zend_is_callable_ex(zcallable, NULL, IS_CALLABLE_STRICT, &func_name, &func_name_len, &fcc, &error TSRMLS_CC)) { - alfi.ce = fcc.calling_scope; - alfi.func_ptr = fcc.function_handler; - obj_ptr = fcc.object_ptr; - if (Z_TYPE_P(zcallable) == IS_ARRAY) { - if (!obj_ptr && alfi.func_ptr && !(alfi.func_ptr->common.fn_flags & ZEND_ACC_STATIC)) { - if (do_throw) { - zend_throw_exception_ex(spl_ce_LogicException, 0 TSRMLS_CC, "Passed array specifies a non static method but no object (%s)", error); - } - if (error) { - efree(error); - } - efree(func_name); - RETURN_FALSE; - } - else if (do_throw) { - zend_throw_exception_ex(spl_ce_LogicException, 0 TSRMLS_CC, "Passed array does not specify %s %smethod (%s)", alfi.func_ptr ? "a callable" : "an existing", !obj_ptr ? "static " : "", error); - } - if (error) { - efree(error); - } - efree(func_name); - RETURN_FALSE; - } else if (Z_TYPE_P(zcallable) == IS_STRING) { - if (do_throw) { - zend_throw_exception_ex(spl_ce_LogicException, 0 TSRMLS_CC, "Function '%s' not %s (%s)", func_name, alfi.func_ptr ? "callable" : "found", error); - } - if (error) { - efree(error); - } - efree(func_name); - RETURN_FALSE; - } else { + func = emalloc(sizeof(zend_autoload_func)); + func->type = ZEND_AUTOLOAD_CLASS; + + if (!ZEND_NUM_ARGS()) { + MAKE_STD_ZVAL(zcallable); + ZVAL_STRING(zcallable, "spl_autoload", 1); + } + + if (zend_fcall_info_init(zcallable, IS_CALLABLE_STRICT, &func->fci, &func->fcc, NULL, &error) == FAILURE) { + if (Z_TYPE_P(zcallable) == IS_ARRAY) { + if (!func->fcc.object_ptr && func->fcc.function_handler && !(func->fcc.function_handler->common.fn_flags & ZEND_ACC_STATIC)) { if (do_throw) { - zend_throw_exception_ex(spl_ce_LogicException, 0 TSRMLS_CC, "Illegal value passed (%s)", error); + zend_throw_exception_ex(spl_ce_LogicException, 0 TSRMLS_CC, "Passed array specifies a non static method but no object (%s)", error); } + efree(func); if (error) { efree(error); } - efree(func_name); RETURN_FALSE; } - } - alfi.closure = NULL; - alfi.ce = fcc.calling_scope; - alfi.func_ptr = fcc.function_handler; - obj_ptr = fcc.object_ptr; - if (error) { - efree(error); - } - - lc_name = safe_emalloc(func_name_len, 1, sizeof(long) + 1); - zend_str_tolower_copy(lc_name, func_name, func_name_len); - efree(func_name); - - if (Z_TYPE_P(zcallable) == IS_OBJECT) { - alfi.closure = zcallable; - Z_ADDREF_P(zcallable); - - lc_name = erealloc(lc_name, func_name_len + 2 + sizeof(zend_object_handle)); - memcpy(lc_name + func_name_len, &Z_OBJ_HANDLE_P(zcallable), - sizeof(zend_object_handle)); - func_name_len += sizeof(zend_object_handle); - lc_name[func_name_len] = '\0'; - } - - if (SPL_G(autoload_functions) && zend_hash_exists(SPL_G(autoload_functions), (char*)lc_name, func_name_len+1)) { - if (alfi.closure) { - Z_DELREF_P(zcallable); + else if (do_throw) { + zend_throw_exception_ex(spl_ce_LogicException, 0 TSRMLS_CC, "Passed array does not specify %s %smethod (%s)", func->fcc.function_handler ? "a callable" : "an existing", !func->fcc.object_ptr ? "static " : "", error); } - goto skip; - } - - if (obj_ptr && !(alfi.func_ptr->common.fn_flags & ZEND_ACC_STATIC)) { - /* add object id to the hash to ensure uniqueness, for more reference look at bug #40091 */ - lc_name = erealloc(lc_name, func_name_len + 2 + sizeof(zend_object_handle)); - memcpy(lc_name + func_name_len, &Z_OBJ_HANDLE_P(obj_ptr), sizeof(zend_object_handle)); - func_name_len += sizeof(zend_object_handle); - lc_name[func_name_len] = '\0'; - alfi.obj = obj_ptr; - Z_ADDREF_P(alfi.obj); + efree(func); + if (error) { + efree(error); + } + RETURN_FALSE; + } else if (Z_TYPE_P(zcallable) == IS_STRING) { + if (do_throw) { + zend_throw_exception_ex(spl_ce_LogicException, 0 TSRMLS_CC, "Function '%s' not %s (%s)", Z_STRVAL_P(zcallable), func->fcc.function_handler ? "callable" : "found", error); + } + efree(func); + if (error) { + efree(error); + } + RETURN_FALSE; } else { - alfi.obj = NULL; - } - - if (!SPL_G(autoload_functions)) { - ALLOC_HASHTABLE(SPL_G(autoload_functions)); - zend_hash_init(SPL_G(autoload_functions), 1, NULL, (dtor_func_t) autoload_func_info_dtor, 0); - } - - zend_hash_find(EG(function_table), "spl_autoload", sizeof("spl_autoload"), (void **) &spl_func_ptr); - - if (EG(autoload_func) == spl_func_ptr) { /* registered already, so we insert that first */ - autoload_func_info spl_alfi; - - spl_alfi.func_ptr = spl_func_ptr; - spl_alfi.obj = NULL; - spl_alfi.ce = NULL; - spl_alfi.closure = NULL; - zend_hash_add(SPL_G(autoload_functions), "spl_autoload", sizeof("spl_autoload"), &spl_alfi, sizeof(autoload_func_info), NULL); - if (prepend && SPL_G(autoload_functions)->nNumOfElements > 1) { - /* Move the newly created element to the head of the hashtable */ - HT_MOVE_TAIL_TO_HEAD(SPL_G(autoload_functions)); + if (do_throw) { + zend_throw_exception_ex(spl_ce_LogicException, 0 TSRMLS_CC, "Illegal value passed (%s)", error); } - } - - if (zend_hash_add(SPL_G(autoload_functions), lc_name, func_name_len+1, &alfi.func_ptr, sizeof(autoload_func_info), NULL) == FAILURE) { - if (obj_ptr && !(alfi.func_ptr->common.fn_flags & ZEND_ACC_STATIC)) { - Z_DELREF_P(alfi.obj); - } - if (alfi.closure) { - Z_DELREF_P(alfi.closure); + efree(func); + if (error) { + efree(error); } + RETURN_FALSE; } - if (prepend && SPL_G(autoload_functions)->nNumOfElements > 1) { - /* Move the newly created element to the head of the hashtable */ - HT_MOVE_TAIL_TO_HEAD(SPL_G(autoload_functions)); - } -skip: - efree(lc_name); + } + func->callable = zcallable; + if (ZEND_NUM_ARGS()) { + Z_ADDREF_P(func->callable); + } + if (error) { + efree(error); } - if (SPL_G(autoload_functions)) { - zend_hash_find(EG(function_table), "spl_autoload_call", sizeof("spl_autoload_call"), (void **) &EG(autoload_func)); - } else { - zend_hash_find(EG(function_table), "spl_autoload", sizeof("spl_autoload"), (void **) &EG(autoload_func)); + if (zend_autoload_register(func, prepend TSRMLS_CC) == FAILURE) { + if (ZEND_NUM_ARGS()) { + Z_DELREF_P(func->callable); + } + efree(func); + RETURN_FALSE; } RETURN_TRUE; } /* }}} */ @@ -628,11 +503,7 @@ PHP_FUNCTION(spl_autoload_unregister) { char *func_name, *error = NULL; int func_name_len; - char *lc_name = NULL; zval *zcallable; - int success = FAILURE; - zend_function *spl_func_ptr; - zval *obj_ptr; zend_fcall_info_cache fcc; if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z", &zcallable) == FAILURE) { @@ -649,54 +520,11 @@ PHP_FUNCTION(spl_autoload_unregister) } RETURN_FALSE; } - obj_ptr = fcc.object_ptr; if (error) { efree(error); } - lc_name = safe_emalloc(func_name_len, 1, sizeof(long) + 1); - zend_str_tolower_copy(lc_name, func_name, func_name_len); - efree(func_name); - - if (Z_TYPE_P(zcallable) == IS_OBJECT) { - lc_name = erealloc(lc_name, func_name_len + 2 + sizeof(zend_object_handle)); - memcpy(lc_name + func_name_len, &Z_OBJ_HANDLE_P(zcallable), - sizeof(zend_object_handle)); - func_name_len += sizeof(zend_object_handle); - lc_name[func_name_len] = '\0'; - } - - if (SPL_G(autoload_functions)) { - if (func_name_len == sizeof("spl_autoload_call")-1 && !strcmp(lc_name, "spl_autoload_call")) { - /* remove all */ - zend_hash_destroy(SPL_G(autoload_functions)); - FREE_HASHTABLE(SPL_G(autoload_functions)); - SPL_G(autoload_functions) = NULL; - EG(autoload_func) = NULL; - success = SUCCESS; - } else { - /* remove specific */ - success = zend_hash_del(SPL_G(autoload_functions), lc_name, func_name_len+1); - if (success != SUCCESS && obj_ptr) { - lc_name = erealloc(lc_name, func_name_len + 2 + sizeof(zend_object_handle)); - memcpy(lc_name + func_name_len, &Z_OBJ_HANDLE_P(obj_ptr), sizeof(zend_object_handle)); - func_name_len += sizeof(zend_object_handle); - lc_name[func_name_len] = '\0'; - success = zend_hash_del(SPL_G(autoload_functions), lc_name, func_name_len+1); - } - } - } else if (func_name_len == sizeof("spl_autoload")-1 && !strcmp(lc_name, "spl_autoload")) { - /* register single spl_autoload() */ - zend_hash_find(EG(function_table), "spl_autoload", sizeof("spl_autoload"), (void **) &spl_func_ptr); - - if (EG(autoload_func) == spl_func_ptr) { - success = SUCCESS; - EG(autoload_func) = NULL; - } - } - - efree(lc_name); - RETURN_BOOL(success == SUCCESS); + RETURN_BOOL(zend_autoload_unregister(&fcc TSRMLS_CC) == SUCCESS); } /* }}} */ /* {{{ proto false|array spl_autoload_functions() @@ -704,14 +532,12 @@ PHP_FUNCTION(spl_autoload_unregister) PHP_FUNCTION(spl_autoload_functions) { zend_function *fptr; - HashPosition function_pos; - autoload_func_info *alfi; if (zend_parse_parameters_none() == FAILURE) { return; } - if (!EG(autoload_func)) { + if (!EG(autoload_funcs)) { if (zend_hash_find(EG(function_table), ZEND_AUTOLOAD_FUNC_NAME, sizeof(ZEND_AUTOLOAD_FUNC_NAME), (void **) &fptr) == SUCCESS) { array_init(return_value); add_next_index_stringl(return_value, ZEND_AUTOLOAD_FUNC_NAME, sizeof(ZEND_AUTOLOAD_FUNC_NAME)-1, 1); @@ -720,48 +546,8 @@ PHP_FUNCTION(spl_autoload_functions) RETURN_FALSE; } - zend_hash_find(EG(function_table), "spl_autoload_call", sizeof("spl_autoload_call"), (void **) &fptr); - - if (EG(autoload_func) == fptr) { - array_init(return_value); - zend_hash_internal_pointer_reset_ex(SPL_G(autoload_functions), &function_pos); - while(zend_hash_has_more_elements_ex(SPL_G(autoload_functions), &function_pos) == SUCCESS) { - zend_hash_get_current_data_ex(SPL_G(autoload_functions), (void **) &alfi, &function_pos); - if (alfi->closure) { - Z_ADDREF_P(alfi->closure); - add_next_index_zval(return_value, alfi->closure); - } else if (alfi->func_ptr->common.scope) { - zval *tmp; - MAKE_STD_ZVAL(tmp); - array_init(tmp); - - if (alfi->obj) { - Z_ADDREF_P(alfi->obj); - add_next_index_zval(tmp, alfi->obj); - } else { - add_next_index_string(tmp, alfi->ce->name, 1); - } - add_next_index_string(tmp, alfi->func_ptr->common.function_name, 1); - add_next_index_zval(return_value, tmp); - } else { - if (strncmp(alfi->func_ptr->common.function_name, "__lambda_func", sizeof("__lambda_func") - 1)) { - add_next_index_string(return_value, alfi->func_ptr->common.function_name, 1); - } else { - char *key; - uint len; - long dummy; - zend_hash_get_current_key_ex(SPL_G(autoload_functions), &key, &len, &dummy, 0, &function_pos); - add_next_index_stringl(return_value, key, len - 1, 1); - } - } + /* TODO: Update SPL Functions */ - zend_hash_move_forward_ex(SPL_G(autoload_functions), &function_pos); - } - return; - } - - array_init(return_value); - add_next_index_string(return_value, EG(autoload_func)->common.function_name, 1); } /* }}} */ /* {{{ proto string spl_object_hash(object obj) From b2f07349fce355aa393890833f6cab8f285ffdbb Mon Sep 17 00:00:00 2001 From: ircmaxell <ircmaxell@gmail.com> Date: Thu, 29 Aug 2013 21:06:33 -0400 Subject: [PATCH 02/20] More progress --- Zend/zend.h | 1 + Zend/zend_autoload.c | 7 +++++-- Zend/zend_autoload.h | 6 +++--- Zend/zend_constants.c | 10 ++++++++++ Zend/zend_execute.h | 3 +++ Zend/zend_vm_def.h | 10 +++++----- Zend/zend_vm_execute.h | 22 +++++++++++----------- 7 files changed, 38 insertions(+), 21 deletions(-) diff --git a/Zend/zend.h b/Zend/zend.h index 1377fd566594b..326787c7f01af 100644 --- a/Zend/zend.h +++ b/Zend/zend.h @@ -596,6 +596,7 @@ typedef int (*zend_write_func_t)(const char *str, uint str_length); #define IS_LEXICAL_VAR 0x020 #define IS_LEXICAL_REF 0x040 #define IS_CONSTANT_IN_NAMESPACE 0x100 +#define IS_CONSTANT_IN_AUTOLOAD 0x200 /* overloaded elements data types */ #define OE_IS_ARRAY (1<<0) diff --git a/Zend/zend_autoload.c b/Zend/zend_autoload.c index 8f3abb29c172b..84a5906e57f1d 100644 --- a/Zend/zend_autoload.c +++ b/Zend/zend_autoload.c @@ -31,7 +31,7 @@ static char* zend_autoload_get_name_key(zend_fcall_info *fci, int *length, zend_bool *do_free TSRMLS_DC); -int zend_autoload_call(zval* name, long type TSRMLS_DC) +int zend_autoload_call(const zval* name, long type TSRMLS_DC) { zval *ztype, *retval = NULL; char *lc_name; @@ -52,6 +52,9 @@ int zend_autoload_call(zval* name, long type TSRMLS_DC) case ZEND_AUTOLOAD_FUNCTION: symbol_table = EG(function_table); break; + case ZEND_AUTOLOAD_CONSTANT: + symbol_table = EG(zend_constants); + break; default: return FAILURE; } @@ -226,7 +229,7 @@ ZEND_FUNCTION(autoload_register) Z_ADDREF_P(callable); if (!type) { - func->type = ZEND_AUTOLOAD_FUNCTION | ZEND_AUTOLOAD_CLASS; + func->type = ZEND_AUTOLOAD_ALL; } else { func->type = type; } diff --git a/Zend/zend_autoload.h b/Zend/zend_autoload.h index 88f6e12fd3a20..87d4bf54abe7d 100644 --- a/Zend/zend_autoload.h +++ b/Zend/zend_autoload.h @@ -30,11 +30,11 @@ typedef struct { long type; } zend_autoload_func; -int zend_autoload_call(zval* name, long type TSRMLS_DC); +int zend_autoload_call(const zval* name, long type TSRMLS_DC); int zend_autoload_register(zend_autoload_func* func, zend_bool prepend TSRMLS_DC); int zend_autoload_unregister(zval *callable TSRMLS_DC); #define ZEND_AUTOLOAD_CLASS 1 #define ZEND_AUTOLOAD_FUNCTION 2 - - +#define ZEND_AUTOLOAD_CONSTANT 4 +#define ZEND_AUTOLOAD_ALL (~0) diff --git a/Zend/zend_constants.c b/Zend/zend_constants.c index 7718e9de28a39..dc76ec66a6ee8 100644 --- a/Zend/zend_constants.c +++ b/Zend/zend_constants.c @@ -129,6 +129,10 @@ void zend_register_standard_constants(TSRMLS_D) REGISTER_MAIN_LONG_CONSTANT(ZEND_NS_NAME("php", "AUTOLOAD_CLASS"), ZEND_AUTOLOAD_CLASS, CONST_CS | CONST_PERSISTENT); REGISTER_MAIN_LONG_CONSTANT(ZEND_NS_NAME("php", "AUTOLOAD_FUNCTION"), ZEND_AUTOLOAD_FUNCTION, CONST_CS | CONST_PERSISTENT); + REGISTER_MAIN_LONG_CONSTANT(ZEND_NS_NAME("php", "AUTOLOAD_CONSTANT"), ZEND_AUTOLOAD_CONSTANT, CONST_CS | CONST_PERSISTENT); + REGISTER_MAIN_LONG_CONSTANT(ZEND_NS_NAME("php", "AUTOLOAD_ALL"), ZEND_AUTOLOAD_ALL, CONST_CS | CONST_PERSISTENT); + + } @@ -458,6 +462,9 @@ zend_constant *zend_quick_get_constant(const zend_literal *key, ulong flags TSRM key--; if (!zend_get_special_constant(Z_STRVAL(key->constant), Z_STRLEN(key->constant), &c TSRMLS_CC)) { + if (!(flags & IS_CONSTANT_IN_AUTOLOAD) && zend_autoload_call(&key->constant, ZEND_AUTOLOAD_CONSTANT TSRMLS_CC) == SUCCESS) { + return zend_quick_get_constant(key, flags | IS_CONSTANT_IN_AUTOLOAD TSRMLS_CC); + } return NULL; } } @@ -465,6 +472,9 @@ zend_constant *zend_quick_get_constant(const zend_literal *key, ulong flags TSRM } else { key--; if (!zend_get_special_constant(Z_STRVAL(key->constant), Z_STRLEN(key->constant), &c TSRMLS_CC)) { + if (!(flags & IS_CONSTANT_IN_AUTOLOAD) && zend_autoload_call(&key->constant, ZEND_AUTOLOAD_CONSTANT TSRMLS_CC) == SUCCESS) { + return zend_quick_get_constant(key, flags | IS_CONSTANT_IN_AUTOLOAD TSRMLS_CC); + } return NULL; } } diff --git a/Zend/zend_execute.h b/Zend/zend_execute.h index 6e470060d5b9b..43c8f5bc02b0c 100644 --- a/Zend/zend_execute.h +++ b/Zend/zend_execute.h @@ -66,6 +66,9 @@ ZEND_API int zend_lookup_class_ex(const char *name, int name_length, const zend_ ZEND_API int zend_lookup_function(const char *name, int name_length, zend_function **fbc TSRMLS_DC); ZEND_API int zend_lookup_function_ex(const char *name, int name_length, const zend_literal *key, int use_autoload, zend_function **fbc TSRMLS_DC); +#define ZEND_LOOKUP_FUNCTION_BY_NAME(name, name_length, fbc) (zend_hash_find(EG(function_table), (name), (name_length) + 1, (void**) (fbc)) == SUCCESS || zend_lookup_function((name), (name_length), (fbc)) == SUCCESS) +#define ZEND_LOOKUP_FUNCTION_BY_LITERAL(name, name_length, literal, fbc) (zend_hash_quick_find(EG(function_table), (name), (name_length) + 1, Z_HASH_P(literal), (void**) (fbc)) == SUCCESS || zend_lookup_function_ex((name), (name_length), (zend_literal*) (literal), 1, (fbc)) == SUCCESS) + ZEND_API int zend_eval_string(char *str, zval *retval_ptr, char *string_name TSRMLS_DC); ZEND_API int zend_eval_stringl(char *str, int str_len, zval *retval_ptr, char *string_name TSRMLS_DC); ZEND_API int zend_eval_string_ex(char *str, zval *retval_ptr, char *string_name, int handle_exceptions TSRMLS_DC); diff --git a/Zend/zend_vm_def.h b/Zend/zend_vm_def.h index 52b1de40cd7e6..d03706cc41114 100644 --- a/Zend/zend_vm_def.h +++ b/Zend/zend_vm_def.h @@ -2637,7 +2637,7 @@ ZEND_VM_HANDLER(59, ZEND_INIT_FCALL_BY_NAME, ANY, CONST|TMP|VAR|CV) function_name = (zval*)(opline->op2.literal+1); if (CACHED_PTR(opline->op2.literal->cache_slot)) { call->fbc = CACHED_PTR(opline->op2.literal->cache_slot); - } else if (UNEXPECTED(zend_lookup_function_ex(Z_STRVAL_P(function_name), Z_STRLEN_P(function_name), (zend_literal*) function_name, 1, &call->fbc) == FAILURE)) { + } else if (UNEXPECTED(!ZEND_LOOKUP_FUNCTION_BY_LITERAL(Z_STRVAL_P(function_name), Z_STRLEN_P(function_name), function_name, &call->fbc))) { SAVE_OPLINE(); zend_error_noreturn(E_ERROR, "Call to undefined function %s()", Z_STRVAL_P(opline->op2.zv)); } else { @@ -2666,7 +2666,7 @@ ZEND_VM_HANDLER(59, ZEND_INIT_FCALL_BY_NAME, ANY, CONST|TMP|VAR|CV) } else { lcname = zend_str_tolower_dup(function_name_strval, function_name_strlen); } - if (UNEXPECTED(zend_lookup_function(lcname, function_name_strlen, &call->fbc) == FAILURE)) { + if (UNEXPECTED(!ZEND_LOOKUP_FUNCTION_BY_NAME(lcname, function_name_strlen, &call->fbc))) { zend_error_noreturn(E_ERROR, "Call to undefined function %s()", function_name_strval); } efree(lcname); @@ -2783,9 +2783,9 @@ ZEND_VM_HANDLER(69, ZEND_INIT_NS_FCALL_BY_NAME, ANY, CONST) func_name = opline->op2.literal + 1; if (CACHED_PTR(opline->op2.literal->cache_slot)) { call->fbc = CACHED_PTR(opline->op2.literal->cache_slot); - } else if (zend_lookup_function_ex(Z_STRVAL(func_name->constant), Z_STRLEN(func_name->constant), func_name->hash_value, 1, &call->fbc)==FAILURE) { + } else if (!ZEND_LOOKUP_FUNCTION_BY_LITERAL(Z_STRVAL(func_name->constant), Z_STRLEN(func_name->constant), func_name->hash_value, &call->fbc)) { func_name++; - if (UNEXPECTED(zend_lookup_function_ex(Z_STRVAL(func_name->constant), Z_STRLEN(func_name->constant), func_name->hash_value, 1, &call->fbc)==FAILURE)) { + if (UNEXPECTED(!ZEND_LOOKUP_FUNCTION_BY_LITERAL(Z_STRVAL(func_name->constant), Z_STRLEN(func_name->constant), func_name->hash_value, &call->fbc))) { SAVE_OPLINE(); zend_error_noreturn(E_ERROR, "Call to undefined function %s()", Z_STRVAL_P(opline->op2.zv)); } else { @@ -2817,7 +2817,7 @@ ZEND_VM_HANDLER(60, ZEND_DO_FCALL, CONST, ANY) if (CACHED_PTR(opline->op1.literal->cache_slot)) { EX(function_state).function = CACHED_PTR(opline->op1.literal->cache_slot); - } else if (UNEXPECTED(zend_lookup_function_ex(Z_STRVAL_P(fname), Z_STRLEN_P(fname), (zend_literal*) fname, 1, &EX(function_state).function)==FAILURE)) { + } else if (UNEXPECTED(!ZEND_LOOKUP_FUNCTION_BY_LITERAL(Z_STRVAL_P(fname), Z_STRLEN_P(fname), fname, &EX(function_state).function))) { SAVE_OPLINE(); zend_error_noreturn(E_ERROR, "Call to undefined function %s()", fname->value.str.val); } else { diff --git a/Zend/zend_vm_execute.h b/Zend/zend_vm_execute.h index 4f13d7f1aa542..f7bb4866dd31e 100644 --- a/Zend/zend_vm_execute.h +++ b/Zend/zend_vm_execute.h @@ -1220,7 +1220,7 @@ static int ZEND_FASTCALL ZEND_INIT_FCALL_BY_NAME_SPEC_CONST_HANDLER(ZEND_OPCODE function_name = (zval*)(opline->op2.literal+1); if (CACHED_PTR(opline->op2.literal->cache_slot)) { call->fbc = CACHED_PTR(opline->op2.literal->cache_slot); - } else if (UNEXPECTED(zend_lookup_function_ex(Z_STRVAL_P(function_name), Z_STRLEN_P(function_name), (zend_literal*) function_name, 1, &call->fbc) == FAILURE)) { + } else if (UNEXPECTED(!ZEND_LOOKUP_FUNCTION_BY_LITERAL(Z_STRVAL_P(function_name), Z_STRLEN_P(function_name), function_name, &call->fbc))) { SAVE_OPLINE(); zend_error_noreturn(E_ERROR, "Call to undefined function %s()", Z_STRVAL_P(opline->op2.zv)); } else { @@ -1249,7 +1249,7 @@ static int ZEND_FASTCALL ZEND_INIT_FCALL_BY_NAME_SPEC_CONST_HANDLER(ZEND_OPCODE } else { lcname = zend_str_tolower_dup(function_name_strval, function_name_strlen); } - if (UNEXPECTED(zend_lookup_function(lcname, function_name_strlen, &call->fbc) == FAILURE)) { + if (UNEXPECTED(!ZEND_LOOKUP_FUNCTION_BY_NAME(lcname, function_name_strlen, &call->fbc))) { zend_error_noreturn(E_ERROR, "Call to undefined function %s()", function_name_strval); } efree(lcname); @@ -1366,9 +1366,9 @@ static int ZEND_FASTCALL ZEND_INIT_NS_FCALL_BY_NAME_SPEC_CONST_HANDLER(ZEND_OPC func_name = opline->op2.literal + 1; if (CACHED_PTR(opline->op2.literal->cache_slot)) { call->fbc = CACHED_PTR(opline->op2.literal->cache_slot); - } else if (zend_lookup_function_ex(Z_STRVAL(func_name->constant), Z_STRLEN(func_name->constant), func_name->hash_value, 1, &call->fbc)==FAILURE) { + } else if (!ZEND_LOOKUP_FUNCTION_BY_LITERAL(Z_STRVAL(func_name->constant), Z_STRLEN(func_name->constant), func_name->hash_value, &call->fbc)) { func_name++; - if (UNEXPECTED(zend_lookup_function_ex(Z_STRVAL(func_name->constant), Z_STRLEN(func_name->constant), func_name->hash_value, 1, &call->fbc)==FAILURE)) { + if (UNEXPECTED(!ZEND_LOOKUP_FUNCTION_BY_LITERAL(Z_STRVAL(func_name->constant), Z_STRLEN(func_name->constant), func_name->hash_value, &call->fbc))) { SAVE_OPLINE(); zend_error_noreturn(E_ERROR, "Call to undefined function %s()", Z_STRVAL_P(opline->op2.zv)); } else { @@ -1545,7 +1545,7 @@ static int ZEND_FASTCALL ZEND_INIT_FCALL_BY_NAME_SPEC_TMP_HANDLER(ZEND_OPCODE_H function_name = (zval*)(opline->op2.literal+1); if (CACHED_PTR(opline->op2.literal->cache_slot)) { call->fbc = CACHED_PTR(opline->op2.literal->cache_slot); - } else if (UNEXPECTED(zend_lookup_function_ex(Z_STRVAL_P(function_name), Z_STRLEN_P(function_name), (zend_literal*) function_name, 1, &call->fbc) == FAILURE)) { + } else if (UNEXPECTED(!ZEND_LOOKUP_FUNCTION_BY_LITERAL(Z_STRVAL_P(function_name), Z_STRLEN_P(function_name), function_name, &call->fbc))) { SAVE_OPLINE(); zend_error_noreturn(E_ERROR, "Call to undefined function %s()", Z_STRVAL_P(opline->op2.zv)); } else { @@ -1574,7 +1574,7 @@ static int ZEND_FASTCALL ZEND_INIT_FCALL_BY_NAME_SPEC_TMP_HANDLER(ZEND_OPCODE_H } else { lcname = zend_str_tolower_dup(function_name_strval, function_name_strlen); } - if (UNEXPECTED(zend_lookup_function(lcname, function_name_strlen, &call->fbc) == FAILURE)) { + if (UNEXPECTED(!ZEND_LOOKUP_FUNCTION_BY_NAME(lcname, function_name_strlen, &call->fbc))) { zend_error_noreturn(E_ERROR, "Call to undefined function %s()", function_name_strval); } efree(lcname); @@ -1732,7 +1732,7 @@ static int ZEND_FASTCALL ZEND_INIT_FCALL_BY_NAME_SPEC_VAR_HANDLER(ZEND_OPCODE_H function_name = (zval*)(opline->op2.literal+1); if (CACHED_PTR(opline->op2.literal->cache_slot)) { call->fbc = CACHED_PTR(opline->op2.literal->cache_slot); - } else if (UNEXPECTED(zend_lookup_function_ex(Z_STRVAL_P(function_name), Z_STRLEN_P(function_name), (zend_literal*) function_name, 1, &call->fbc) == FAILURE)) { + } else if (UNEXPECTED(!ZEND_LOOKUP_FUNCTION_BY_LITERAL(Z_STRVAL_P(function_name), Z_STRLEN_P(function_name), function_name, &call->fbc))) { SAVE_OPLINE(); zend_error_noreturn(E_ERROR, "Call to undefined function %s()", Z_STRVAL_P(opline->op2.zv)); } else { @@ -1761,7 +1761,7 @@ static int ZEND_FASTCALL ZEND_INIT_FCALL_BY_NAME_SPEC_VAR_HANDLER(ZEND_OPCODE_H } else { lcname = zend_str_tolower_dup(function_name_strval, function_name_strlen); } - if (UNEXPECTED(zend_lookup_function(lcname, function_name_strlen, &call->fbc) == FAILURE)) { + if (UNEXPECTED(!ZEND_LOOKUP_FUNCTION_BY_NAME(lcname, function_name_strlen, &call->fbc))) { zend_error_noreturn(E_ERROR, "Call to undefined function %s()", function_name_strval); } efree(lcname); @@ -1957,7 +1957,7 @@ static int ZEND_FASTCALL ZEND_INIT_FCALL_BY_NAME_SPEC_CV_HANDLER(ZEND_OPCODE_HA function_name = (zval*)(opline->op2.literal+1); if (CACHED_PTR(opline->op2.literal->cache_slot)) { call->fbc = CACHED_PTR(opline->op2.literal->cache_slot); - } else if (UNEXPECTED(zend_lookup_function_ex(Z_STRVAL_P(function_name), Z_STRLEN_P(function_name), (zend_literal*) function_name, 1, &call->fbc) == FAILURE)) { + } else if (UNEXPECTED(!ZEND_LOOKUP_FUNCTION_BY_LITERAL(Z_STRVAL_P(function_name), Z_STRLEN_P(function_name), function_name, &call->fbc))) { SAVE_OPLINE(); zend_error_noreturn(E_ERROR, "Call to undefined function %s()", Z_STRVAL_P(opline->op2.zv)); } else { @@ -1986,7 +1986,7 @@ static int ZEND_FASTCALL ZEND_INIT_FCALL_BY_NAME_SPEC_CV_HANDLER(ZEND_OPCODE_HA } else { lcname = zend_str_tolower_dup(function_name_strval, function_name_strlen); } - if (UNEXPECTED(zend_lookup_function(lcname, function_name_strlen, &call->fbc) == FAILURE)) { + if (UNEXPECTED(!ZEND_LOOKUP_FUNCTION_BY_NAME(lcname, function_name_strlen, &call->fbc))) { zend_error_noreturn(E_ERROR, "Call to undefined function %s()", function_name_strval); } efree(lcname); @@ -2311,7 +2311,7 @@ static int ZEND_FASTCALL ZEND_DO_FCALL_SPEC_CONST_HANDLER(ZEND_OPCODE_HANDLER_A if (CACHED_PTR(opline->op1.literal->cache_slot)) { EX(function_state).function = CACHED_PTR(opline->op1.literal->cache_slot); - } else if (UNEXPECTED(zend_lookup_function_ex(Z_STRVAL_P(fname), Z_STRLEN_P(fname), (zend_literal*) fname, 1, &EX(function_state).function)==FAILURE)) { + } else if (UNEXPECTED(!ZEND_LOOKUP_FUNCTION_BY_LITERAL(Z_STRVAL_P(fname), Z_STRLEN_P(fname), fname, &EX(function_state).function))) { SAVE_OPLINE(); zend_error_noreturn(E_ERROR, "Call to undefined function %s()", fname->value.str.val); } else { From d10dc034a370ba87c53c90bbdb020f2d88a90800 Mon Sep 17 00:00:00 2001 From: Anthony Ferrara <ircmaxell@gmail.com> Date: Fri, 30 Aug 2013 11:34:05 -0400 Subject: [PATCH 03/20] More work, fixing memleaks and behavior --- Zend/zend_autoload.c | 19 +++++++++++-------- Zend/zend_builtin_functions.c | 2 +- Zend/zend_execute_API.c | 4 ++-- Zend/zend_vm_def.h | 4 ++-- Zend/zend_vm_execute.h | 4 ++-- ext/spl/php_spl.c | 3 ++- 6 files changed, 20 insertions(+), 16 deletions(-) diff --git a/Zend/zend_autoload.c b/Zend/zend_autoload.c index 84a5906e57f1d..28d2ecbd2e312 100644 --- a/Zend/zend_autoload.c +++ b/Zend/zend_autoload.c @@ -30,6 +30,7 @@ #include "zend_exceptions.h" static char* zend_autoload_get_name_key(zend_fcall_info *fci, int *length, zend_bool *do_free TSRMLS_DC); +static void zend_autoload_func_dtor(zend_autoload_func *func); int zend_autoload_call(const zval* name, long type TSRMLS_DC) { @@ -112,7 +113,7 @@ int zend_autoload_call(const zval* name, long type TSRMLS_DC) } zend_exception_restore(TSRMLS_C); - Z_DELREF_P(ztype); + zval_ptr_dtor(&ztype); zend_hash_del(EG(autoload_stack), lc_name, lc_length); efree(lc_name); return SUCCESS; @@ -146,6 +147,12 @@ static char* zend_autoload_get_name_key(zend_fcall_info *fci, int *length, zend_ } } +static void zend_autoload_func_dtor(zend_autoload_func *func) { + if (func->callable) { + zval_ptr_dtor(&func->callable); + } +} + int zend_autoload_register(zend_autoload_func *func, zend_bool prepend TSRMLS_DC) { char *lc_name; @@ -155,17 +162,14 @@ int zend_autoload_register(zend_autoload_func *func, zend_bool prepend TSRMLS_DC lc_name = zend_autoload_get_name_key(&func->fci, &lc_length, &do_free); if (lc_name == 0) { zend_error_noreturn(E_ERROR, "Unknown Function Name Type Provided"); - } else if (do_free) { - Z_ADDREF_P(func->callable); } if (!EG(autoload_funcs)) { ALLOC_HASHTABLE(EG(autoload_funcs)); - zend_hash_init(EG(autoload_funcs), 0, NULL, NULL, 0); + zend_hash_init(EG(autoload_funcs), 1, NULL, (dtor_func_t) zend_autoload_func_dtor, 0); } else if (zend_hash_exists(EG(autoload_funcs), lc_name, lc_length + 1)) { if (do_free) { efree(lc_name); - Z_DELREF_P(func->callable); } return FAILURE; } @@ -177,7 +181,6 @@ int zend_autoload_register(zend_autoload_func *func, zend_bool prepend TSRMLS_DC } if (do_free) { efree(lc_name); - Z_DELREF_P(func->callable); } return status; } @@ -235,9 +238,9 @@ ZEND_FUNCTION(autoload_register) } if (zend_autoload_register(func, prepend TSRMLS_CC) == FAILURE) { - Z_DELREF_P(callable); - efree(func); + zval_ptr_dtor(&callable); } + efree(func); } ZEND_FUNCTION(autoload_unregister) diff --git a/Zend/zend_builtin_functions.c b/Zend/zend_builtin_functions.c index d6de0037bb091..d967a6adac3ca 100644 --- a/Zend/zend_builtin_functions.c +++ b/Zend/zend_builtin_functions.c @@ -1380,7 +1380,7 @@ ZEND_FUNCTION(function_exists) name_len--; } - retval = (zend_lookup_function_ex(name, name_len+1, NULL, (int) autoload, &func) == SUCCESS); + retval = (zend_lookup_function_ex(name, name_len, NULL, (int) autoload, &func) == SUCCESS); efree(lcname); diff --git a/Zend/zend_execute_API.c b/Zend/zend_execute_API.c index 80048ecb325fe..e714ffa7ceecb 100644 --- a/Zend/zend_execute_API.c +++ b/Zend/zend_execute_API.c @@ -1065,8 +1065,7 @@ ZEND_API int zend_lookup_function_ex(const char *name, int name_length, const ze return FAILURE; } - ALLOC_ZVAL(function_name_ptr); - INIT_PZVAL(function_name_ptr); + ALLOC_INIT_ZVAL(function_name_ptr); if (name[0] == '\\') { ZVAL_STRINGL(function_name_ptr, name+1, name_length-1, 1); } else { @@ -1076,6 +1075,7 @@ ZEND_API int zend_lookup_function_ex(const char *name, int name_length, const ze zend_hash_quick_find(EG(function_table), lc_name, lc_length, hash, (void **) fbc) == SUCCESS) { retval = SUCCESS; } + zval_ptr_dtor(&function_name_ptr); if (!key) { free_alloca(lc_free, use_heap); diff --git a/Zend/zend_vm_def.h b/Zend/zend_vm_def.h index d03706cc41114..ece52b2f029af 100644 --- a/Zend/zend_vm_def.h +++ b/Zend/zend_vm_def.h @@ -2783,9 +2783,9 @@ ZEND_VM_HANDLER(69, ZEND_INIT_NS_FCALL_BY_NAME, ANY, CONST) func_name = opline->op2.literal + 1; if (CACHED_PTR(opline->op2.literal->cache_slot)) { call->fbc = CACHED_PTR(opline->op2.literal->cache_slot); - } else if (!ZEND_LOOKUP_FUNCTION_BY_LITERAL(Z_STRVAL(func_name->constant), Z_STRLEN(func_name->constant), func_name->hash_value, &call->fbc)) { + } else if (UNEXPECTED(zend_hash_quick_find(EG(function_table), Z_STRVAL(func_name->constant), Z_STRLEN(func_name->constant) + 1, func_name->hash_value, (void**) &call->fbc) == FAILURE)) { func_name++; - if (UNEXPECTED(!ZEND_LOOKUP_FUNCTION_BY_LITERAL(Z_STRVAL(func_name->constant), Z_STRLEN(func_name->constant), func_name->hash_value, &call->fbc))) { + if (UNEXPECTED(!ZEND_LOOKUP_FUNCTION_BY_LITERAL(Z_STRVAL(func_name->constant), Z_STRLEN(func_name->constant), func_name, &call->fbc))) { SAVE_OPLINE(); zend_error_noreturn(E_ERROR, "Call to undefined function %s()", Z_STRVAL_P(opline->op2.zv)); } else { diff --git a/Zend/zend_vm_execute.h b/Zend/zend_vm_execute.h index f7bb4866dd31e..71e357480995c 100644 --- a/Zend/zend_vm_execute.h +++ b/Zend/zend_vm_execute.h @@ -1366,9 +1366,9 @@ static int ZEND_FASTCALL ZEND_INIT_NS_FCALL_BY_NAME_SPEC_CONST_HANDLER(ZEND_OPC func_name = opline->op2.literal + 1; if (CACHED_PTR(opline->op2.literal->cache_slot)) { call->fbc = CACHED_PTR(opline->op2.literal->cache_slot); - } else if (!ZEND_LOOKUP_FUNCTION_BY_LITERAL(Z_STRVAL(func_name->constant), Z_STRLEN(func_name->constant), func_name->hash_value, &call->fbc)) { + } else if (UNEXPECTED(zend_hash_quick_find(EG(function_table), Z_STRVAL(func_name->constant), Z_STRLEN(func_name->constant) + 1, func_name->hash_value, (void**) &call->fbc) == FAILURE)) { func_name++; - if (UNEXPECTED(!ZEND_LOOKUP_FUNCTION_BY_LITERAL(Z_STRVAL(func_name->constant), Z_STRLEN(func_name->constant), func_name->hash_value, &call->fbc))) { + if (UNEXPECTED(!ZEND_LOOKUP_FUNCTION_BY_LITERAL(Z_STRVAL(func_name->constant), Z_STRLEN(func_name->constant), func_name, &call->fbc))) { SAVE_OPLINE(); zend_error_noreturn(E_ERROR, "Call to undefined function %s()", Z_STRVAL_P(opline->op2.zv)); } else { diff --git a/ext/spl/php_spl.c b/ext/spl/php_spl.c index 8ce82168297d8..ddfbbd7dd227e 100644 --- a/ext/spl/php_spl.c +++ b/ext/spl/php_spl.c @@ -489,11 +489,12 @@ PHP_FUNCTION(spl_autoload_register) if (zend_autoload_register(func, prepend TSRMLS_CC) == FAILURE) { if (ZEND_NUM_ARGS()) { - Z_DELREF_P(func->callable); + zval_ptr_dtor(&func->callable); } efree(func); RETURN_FALSE; } + efree(func); RETURN_TRUE; } /* }}} */ From 5e71fb581f82cb3fd19da70731d6617113f08ea0 Mon Sep 17 00:00:00 2001 From: Anthony Ferrara <ircmaxell@gmail.com> Date: Fri, 30 Aug 2013 13:27:20 -0400 Subject: [PATCH 04/20] Refactor out the lookup in is_callable --- Zend/zend_API.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Zend/zend_API.c b/Zend/zend_API.c index c657c20b6687e..28143e6ffcf5b 100644 --- a/Zend/zend_API.c +++ b/Zend/zend_API.c @@ -2764,7 +2764,7 @@ static int zend_is_callable_check_func(int check_flags, zval *callable, zend_fca } /* Check if function with given name exists. * This may be a compound name that includes namespace name */ - if (zend_lookup_function(lmname, mlen, (void**)&fcc->function_handler) == SUCCESS) { + if (ZEND_LOOKUP_FUNCTION_BY_NAME(lmname, mlen, &fcc->function_handler)) { efree(lmname); return 1; } From 2efdc970f051eb69352252e4ff45fa5ba16ff7ec Mon Sep 17 00:00:00 2001 From: Anthony Ferrara <ircmaxell@gmail.com> Date: Fri, 30 Aug 2013 13:35:25 -0400 Subject: [PATCH 05/20] Remove lowercasing components --- Zend/zend_execute_API.c | 29 +++++++---------------------- 1 file changed, 7 insertions(+), 22 deletions(-) diff --git a/Zend/zend_execute_API.c b/Zend/zend_execute_API.c index e714ffa7ceecb..bea33d3a53bb4 100644 --- a/Zend/zend_execute_API.c +++ b/Zend/zend_execute_API.c @@ -1022,12 +1022,13 @@ ZEND_API int zend_lookup_function(const char *name, int name_length, zend_functi ZEND_API int zend_lookup_function_ex(const char *name, int name_length, const zend_literal *key, int use_autoload, zend_function **fbc TSRMLS_DC) { - char *lc_name, *lc_free; - int lc_length, retval = FAILURE; + char *lc_name; + int lc_length; + int retval = FAILURE; zend_ulong hash; - ALLOCA_FLAG(use_heap) zval *function_name_ptr; + if (key) { lc_name = Z_STRVAL(key->constant); lc_length = Z_STRLEN(key->constant) + 1; @@ -1036,22 +1037,12 @@ ZEND_API int zend_lookup_function_ex(const char *name, int name_length, const ze if (name == NULL || !name_length) { return FAILURE; } - - 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; - } - + lc_name = name; + lc_length = name_length; hash = zend_inline_hash_func(lc_name, lc_length); } if (zend_hash_quick_find(EG(function_table), lc_name, lc_length, hash, (void **) fbc) == SUCCESS) { - if (!key) { - free_alloca(lc_free, use_heap); - } + return SUCCESS; } @@ -1059,9 +1050,6 @@ ZEND_API int zend_lookup_function_ex(const char *name, int name_length, const ze * (doesn't impact functionality of __autoload_function() */ if (!use_autoload || zend_is_compiling(TSRMLS_C)) { - if (!key) { - free_alloca(lc_free, use_heap); - } return FAILURE; } @@ -1077,9 +1065,6 @@ ZEND_API int zend_lookup_function_ex(const char *name, int name_length, const ze } zval_ptr_dtor(&function_name_ptr); - if (!key) { - free_alloca(lc_free, use_heap); - } return retval; } From 6aa5b0370965e03284deced557d99d250046ff6e Mon Sep 17 00:00:00 2001 From: Anthony Ferrara <ircmaxell@gmail.com> Date: Fri, 30 Aug 2013 14:09:26 -0400 Subject: [PATCH 06/20] Fix memory leak, and clean up a bit --- Zend/zend_autoload.c | 1 + Zend/zend_execute_API.c | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/Zend/zend_autoload.c b/Zend/zend_autoload.c index 28d2ecbd2e312..a42c8b321bd76 100644 --- a/Zend/zend_autoload.c +++ b/Zend/zend_autoload.c @@ -111,6 +111,7 @@ int zend_autoload_call(const zval* name, long type TSRMLS_DC) } zend_hash_move_forward_ex(EG(autoload_funcs), &function_pos); } + zend_fcall_info_args_clear(&func_info->fci, 1); zend_exception_restore(TSRMLS_C); zval_ptr_dtor(&ztype); diff --git a/Zend/zend_execute_API.c b/Zend/zend_execute_API.c index bea33d3a53bb4..e58898bb33127 100644 --- a/Zend/zend_execute_API.c +++ b/Zend/zend_execute_API.c @@ -1127,7 +1127,7 @@ ZEND_API int zend_lookup_class_ex(const char *name, int name_length, const zend_ zend_hash_quick_find(EG(class_table), lc_name, lc_length, hash, (void **) ce) == SUCCESS) { retval = SUCCESS; } - + zval_ptr_dtor(&class_name_ptr); if (!key) { free_alloca(lc_free, use_heap); } From cdac9d7c6412a04dcd5b49a2e11b638a82399530 Mon Sep 17 00:00:00 2001 From: krakjoe <joe.watkins@live.co.uk> Date: Sat, 21 Dec 2013 20:18:22 +0000 Subject: [PATCH 07/20] fix build --- Zend/zend_execute_API.c | 3 +++ Zend/zend_globals.h | 1 + Zend/zend_vm_opcodes.h | 2 +- 3 files changed, 5 insertions(+), 1 deletion(-) diff --git a/Zend/zend_execute_API.c b/Zend/zend_execute_API.c index 6bf17088b9c72..4fc10e6b6d0c8 100644 --- a/Zend/zend_execute_API.c +++ b/Zend/zend_execute_API.c @@ -1084,11 +1084,14 @@ ZEND_API int zend_lookup_function_ex(const char *name, int name_length, const ze 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) /* {{{ */ { + zval autoload_function; zval *class_name_ptr; int lc_length, retval = FAILURE; char *lc_name; char *lc_free; ulong hash; + char dummy = 1; + ALLOCA_FLAG(use_heap) if (key) { diff --git a/Zend/zend_globals.h b/Zend/zend_globals.h index 051916ecae6f4..04ce8b4a7109b 100644 --- a/Zend/zend_globals.h +++ b/Zend/zend_globals.h @@ -207,6 +207,7 @@ struct _zend_executor_globals { zend_bool in_execution; HashTable *autoload_stack; HashTable *autoload_funcs; + HashTable *in_autoload; zend_function *autoload_legacy; zend_bool full_tables_cleanup; diff --git a/Zend/zend_vm_opcodes.h b/Zend/zend_vm_opcodes.h index 663e216183001..184462d51e681 100644 --- a/Zend/zend_vm_opcodes.h +++ b/Zend/zend_vm_opcodes.h @@ -337,4 +337,4 @@ const char *zend_vm_opcodes_map[] = { "ZEND_RECV_VARIADIC", }; -#endif \ No newline at end of file +#endif From 8657f772269b0f031470c66d280484397d2129db Mon Sep 17 00:00:00 2001 From: krakjoe <joe.watkins@live.co.uk> Date: Sat, 21 Dec 2013 20:42:02 +0000 Subject: [PATCH 08/20] fix call to unload --- ext/spl/php_spl.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ext/spl/php_spl.c b/ext/spl/php_spl.c index ddfbbd7dd227e..8bf633adaf57e 100644 --- a/ext/spl/php_spl.c +++ b/ext/spl/php_spl.c @@ -525,7 +525,7 @@ PHP_FUNCTION(spl_autoload_unregister) efree(error); } - RETURN_BOOL(zend_autoload_unregister(&fcc TSRMLS_CC) == SUCCESS); + RETURN_BOOL(zend_autoload_unregister(zcallable TSRMLS_CC) == SUCCESS); } /* }}} */ /* {{{ proto false|array spl_autoload_functions() From 8a73ed4bc9382dde15da3b868b94be45fceb0b73 Mon Sep 17 00:00:00 2001 From: krakjoe <joe.watkins@live.co.uk> Date: Sat, 21 Dec 2013 21:21:33 +0000 Subject: [PATCH 09/20] fix build --- Zend/zend_execute_API.c | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/Zend/zend_execute_API.c b/Zend/zend_execute_API.c index 4fc10e6b6d0c8..5436b6b71310d 100644 --- a/Zend/zend_execute_API.c +++ b/Zend/zend_execute_API.c @@ -1090,8 +1090,6 @@ ZEND_API int zend_lookup_class_ex(const char *name, int name_length, const zend_ char *lc_name; char *lc_free; ulong hash; - char dummy = 1; - ALLOCA_FLAG(use_heap) if (key) { @@ -1145,12 +1143,18 @@ ZEND_API int zend_lookup_class_ex(const char *name, int name_length, const zend_ zend_hash_init(EG(in_autoload), 0, NULL, NULL, 0); } - if (zend_hash_quick_add(EG(in_autoload), lc_name, lc_length, hash, (void**)&dummy, sizeof(char), NULL) == FAILURE) { - if (!key) { - free_alloca(lc_free, use_heap); + + { + char unused = 1; + + if (zend_hash_quick_add(EG(in_autoload), lc_name, lc_length, hash, (void**)&unused, sizeof(char), NULL) == FAILURE) { + if (!key) { + free_alloca(lc_free, use_heap); + } + return FAILURE; } - return FAILURE; } + ZVAL_STRINGL(&autoload_function, ZEND_AUTOLOAD_FUNC_NAME, sizeof(ZEND_AUTOLOAD_FUNC_NAME) - 1, 0); From f16b075dbde494516635c6c0f385d87f0e50322a Mon Sep 17 00:00:00 2001 From: krakjoe <joe.watkins@live.co.uk> Date: Sat, 21 Dec 2013 22:16:20 +0000 Subject: [PATCH 10/20] fix patch, run tests --- Zend/zend.c | 2 ++ Zend/zend_builtin_functions.c | 2 +- Zend/zend_execute_API.c | 11 +++++++---- 3 files changed, 10 insertions(+), 5 deletions(-) diff --git a/Zend/zend.c b/Zend/zend.c index ad45028d4be85..bd71269cd4ef0 100644 --- a/Zend/zend.c +++ b/Zend/zend.c @@ -581,6 +581,8 @@ static void executor_globals_ctor(zend_executor_globals *executor_globals TSRMLS #endif EG(saved_fpu_cw_ptr) = NULL; EG(active) = 0; + EG(autoload_legacy) = NULL; + EG(autoload_stack) = NULL; } /* }}} */ diff --git a/Zend/zend_builtin_functions.c b/Zend/zend_builtin_functions.c index 9e95194fe5950..f60c1b1aa8e3e 100644 --- a/Zend/zend_builtin_functions.c +++ b/Zend/zend_builtin_functions.c @@ -1390,7 +1390,7 @@ ZEND_FUNCTION(function_exists) name_len--; } - retval = (zend_lookup_function_ex(name, name_len, NULL, (int) autoload, &func) == SUCCESS); + retval = (zend_lookup_function_ex(lcname, name_len+1, NULL, (int) autoload, &func) == SUCCESS); efree(lcname); diff --git a/Zend/zend_execute_API.c b/Zend/zend_execute_API.c index 5436b6b71310d..af97cc3345ea0 100644 --- a/Zend/zend_execute_API.c +++ b/Zend/zend_execute_API.c @@ -1054,8 +1054,8 @@ ZEND_API int zend_lookup_function_ex(const char *name, int name_length, const ze lc_length = name_length; hash = zend_inline_hash_func(lc_name, lc_length); } + if (zend_hash_quick_find(EG(function_table), lc_name, lc_length, hash, (void **) fbc) == SUCCESS) { - return SUCCESS; } @@ -1072,10 +1072,13 @@ ZEND_API int zend_lookup_function_ex(const char *name, int name_length, const ze } else { ZVAL_STRINGL(function_name_ptr, name, name_length, 1); } - if (zend_autoload_call(function_name_ptr, ZEND_AUTOLOAD_FUNCTION TSRMLS_CC) == SUCCESS && - zend_hash_quick_find(EG(function_table), lc_name, lc_length, hash, (void **) fbc) == SUCCESS) { - retval = SUCCESS; + + if (zend_autoload_call(function_name_ptr, ZEND_AUTOLOAD_FUNCTION TSRMLS_CC) != SUCCESS) { + /* do something, or not */ } + + retval = zend_hash_quick_find( + EG(function_table), lc_name, lc_length, hash, (void **) fbc); zval_ptr_dtor(&function_name_ptr); return retval; From dfa13d9a24c11ca67a7fdd8ab2428eaee6525f6e Mon Sep 17 00:00:00 2001 From: krakjoe <joe.watkins@live.co.uk> Date: Sat, 21 Dec 2013 22:26:24 +0000 Subject: [PATCH 11/20] plug leaks --- Zend/zend.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/Zend/zend.c b/Zend/zend.c index bd71269cd4ef0..dca072e129c6b 100644 --- a/Zend/zend.c +++ b/Zend/zend.c @@ -966,6 +966,16 @@ ZEND_API void zend_deactivate(TSRMLS_D) /* {{{ */ } #endif + if (EG(autoload_stack)) { + zend_hash_destroy(EG(autoload_stack)); + FREE_HASHTABLE(EG(autoload_stack)); + } + + if (EG(in_autoload)) { + zend_hash_destroy(EG(in_autoload)); + FREE_HASHTABLE(EG(in_autoload)); + } + #if GC_BENCH fprintf(stderr, "GC Statistics\n"); fprintf(stderr, "-------------\n"); From c34abb56fe57719eca9be6010f4a3182ba4a1fa5 Mon Sep 17 00:00:00 2001 From: krakjoe <joe.watkins@live.co.uk> Date: Sun, 22 Dec 2013 07:48:48 +0000 Subject: [PATCH 12/20] fix most tests in Zend, three remain --- Zend/zend.c | 10 ---------- Zend/zend_autoload.c | 10 ++++++++-- Zend/zend_builtin_functions.c | 2 +- Zend/zend_execute_API.c | 12 ++++++++++++ 4 files changed, 21 insertions(+), 13 deletions(-) diff --git a/Zend/zend.c b/Zend/zend.c index dca072e129c6b..bd71269cd4ef0 100644 --- a/Zend/zend.c +++ b/Zend/zend.c @@ -966,16 +966,6 @@ ZEND_API void zend_deactivate(TSRMLS_D) /* {{{ */ } #endif - if (EG(autoload_stack)) { - zend_hash_destroy(EG(autoload_stack)); - FREE_HASHTABLE(EG(autoload_stack)); - } - - if (EG(in_autoload)) { - zend_hash_destroy(EG(in_autoload)); - FREE_HASHTABLE(EG(in_autoload)); - } - #if GC_BENCH fprintf(stderr, "GC Statistics\n"); fprintf(stderr, "-------------\n"); diff --git a/Zend/zend_autoload.c b/Zend/zend_autoload.c index a42c8b321bd76..6d32f84076f4b 100644 --- a/Zend/zend_autoload.c +++ b/Zend/zend_autoload.c @@ -67,14 +67,20 @@ int zend_autoload_call(const zval* name, long type TSRMLS_DC) if (type == ZEND_AUTOLOAD_CLASS && ( EG(autoload_legacy) != NULL - || zend_lookup_function_ex(ZEND_AUTOLOAD_FUNC_NAME, sizeof(ZEND_AUTOLOAD_FUNC_NAME) - 1, NULL, 0, &EG(autoload_legacy) TSRMLS_CC) == SUCCESS + || zend_lookup_function_ex(ZEND_AUTOLOAD_FUNC_NAME, sizeof(ZEND_AUTOLOAD_FUNC_NAME), NULL, 0, &EG(autoload_legacy) TSRMLS_CC) == SUCCESS ) ) { - zend_call_method_with_1_params(NULL, NULL, &EG(autoload_legacy), ZEND_AUTOLOAD_FUNC_NAME, &retval, name); + zend_call_method_with_1_params(NULL, NULL, &EG(autoload_legacy), ZEND_AUTOLOAD_FUNC_NAME, &retval, (zval*) name); if (zend_hash_exists(symbol_table, lc_name, lc_length + 1)) { + if (retval) { + zval_ptr_dtor(&retval); + } efree(lc_name); return SUCCESS; } + if (retval) { + zval_ptr_dtor(&retval); + } } efree(lc_name); return FAILURE; diff --git a/Zend/zend_builtin_functions.c b/Zend/zend_builtin_functions.c index f60c1b1aa8e3e..4c2030f42b703 100644 --- a/Zend/zend_builtin_functions.c +++ b/Zend/zend_builtin_functions.c @@ -1390,7 +1390,7 @@ ZEND_FUNCTION(function_exists) name_len--; } - retval = (zend_lookup_function_ex(lcname, name_len+1, NULL, (int) autoload, &func) == SUCCESS); + retval = (zend_lookup_function_ex(name, name_len+1, NULL, (int) autoload, &func) == SUCCESS); efree(lcname); diff --git a/Zend/zend_execute_API.c b/Zend/zend_execute_API.c index af97cc3345ea0..fc007c38eef52 100644 --- a/Zend/zend_execute_API.c +++ b/Zend/zend_execute_API.c @@ -326,13 +326,25 @@ void shutdown_executor(TSRMLS_D) /* {{{ */ zend_ptr_stack_destroy(&EG(user_error_handlers)); zend_ptr_stack_destroy(&EG(user_exception_handlers)); zend_objects_store_destroy(&EG(objects_store)); + + } zend_end_try(); + + zend_try { + /* shutdown autoload */ if (EG(autoload_stack)) { zend_hash_destroy(EG(autoload_stack)); FREE_HASHTABLE(EG(autoload_stack)); + EG(autoload_stack) = NULL; } if (EG(autoload_funcs)) { zend_hash_destroy(EG(autoload_funcs)); FREE_HASHTABLE(EG(autoload_funcs)); + EG(autoload_funcs) = NULL; + } + if (EG(in_autoload)) { + zend_hash_destroy(EG(in_autoload)); + FREE_HASHTABLE(EG(in_autoload)); + EG(in_autoload) = NULL; } } zend_end_try(); From cfa2f6f627e4c7bbafc201e935484362a3da1bbb Mon Sep 17 00:00:00 2001 From: krakjoe <joe.watkins@live.co.uk> Date: Sun, 22 Dec 2013 09:00:59 +0000 Subject: [PATCH 13/20] fix register autoload array callable --- Zend/zend_autoload.c | 26 ++++++++++++++++++++++---- 1 file changed, 22 insertions(+), 4 deletions(-) diff --git a/Zend/zend_autoload.c b/Zend/zend_autoload.c index 6d32f84076f4b..c2eaba07ddcda 100644 --- a/Zend/zend_autoload.c +++ b/Zend/zend_autoload.c @@ -29,7 +29,7 @@ #include "zend_interfaces.h" #include "zend_exceptions.h" -static char* zend_autoload_get_name_key(zend_fcall_info *fci, int *length, zend_bool *do_free TSRMLS_DC); +static char* zend_autoload_get_name_key(zend_fcall_info *fci, zend_fcall_info_cache *fcc, int *length, zend_bool *do_free TSRMLS_DC); static void zend_autoload_func_dtor(zend_autoload_func *func); int zend_autoload_call(const zval* name, long type TSRMLS_DC) @@ -134,7 +134,7 @@ int zend_autoload_call(const zval* name, long type TSRMLS_DC) (ht)->pListTail->pListNext = NULL; \ (ht)->pListHead->pListLast = NULL; -static char* zend_autoload_get_name_key(zend_fcall_info *fci, int *length, zend_bool *do_free TSRMLS_DC) { +static char* zend_autoload_get_name_key(zend_fcall_info *fci, zend_fcall_info_cache *fcc, int *length, zend_bool *do_free TSRMLS_DC) { char *name; switch (Z_TYPE_P(fci->function_name)) { case IS_STRING: @@ -149,6 +149,24 @@ static char* zend_autoload_get_name_key(zend_fcall_info *fci, int *length, zend_ name[*length] = '\0'; return name; break; + case IS_ARRAY: + if (fcc->function_handler->common.scope) { + zend_function *func = fcc->function_handler; + zend_class_entry *ce = func->common.scope; + + *do_free = 1; + if (ce) { + *length = strlen(func->common.function_name) + ce->name_length + 2; + name = emalloc(*length + 1); + memcpy(name, ce->name, ce->name_length); + memcpy(&name[ce->name_length], "::", sizeof("::")-1); + memcpy(&name[ce->name_length+sizeof("::")-1], + func->common.function_name, strlen(func->common.function_name)); + name[*length] = 0; + return name; + } + } + break; default: return 0; } @@ -166,7 +184,7 @@ int zend_autoload_register(zend_autoload_func *func, zend_bool prepend TSRMLS_DC zend_bool do_free = 0; int lc_length, status = SUCCESS; - lc_name = zend_autoload_get_name_key(&func->fci, &lc_length, &do_free); + lc_name = zend_autoload_get_name_key(&func->fci, &func->fcc, &lc_length, &do_free); if (lc_name == 0) { zend_error_noreturn(E_ERROR, "Unknown Function Name Type Provided"); } @@ -204,7 +222,7 @@ int zend_autoload_unregister(zval *callable TSRMLS_DC) return FAILURE; } - lc_name = zend_autoload_get_name_key(&fci, &lc_length, &do_free); + lc_name = zend_autoload_get_name_key(&fci, &fcc, &lc_length, &do_free); if (lc_name == 0) { return FAILURE; } From 3cf2f1f1c05bd43d92789f098dec4eff74fd6807 Mon Sep 17 00:00:00 2001 From: krakjoe <joe.watkins@live.co.uk> Date: Sun, 22 Dec 2013 09:06:33 +0000 Subject: [PATCH 14/20] fix error conditions test, prototype for function_exists --- Zend/tests/function_exists_error.phpt | 6 +++--- Zend/zend_builtin_functions.c | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/Zend/tests/function_exists_error.phpt b/Zend/tests/function_exists_error.phpt index cbc3908f12b30..1a696d47c171b 100644 --- a/Zend/tests/function_exists_error.phpt +++ b/Zend/tests/function_exists_error.phpt @@ -13,7 +13,7 @@ $arg_0 = "ABC"; $extra_arg = 1; echo "\nToo many arguments\n"; -var_dump(function_exists($arg_0, $extra_arg)); +var_dump(function_exists($arg_0, true, $extra_arg)); echo "\nToo few arguments\n"; var_dump(function_exists()); @@ -25,12 +25,12 @@ var_dump(function_exists()); Too many arguments -Warning: function_exists() expects exactly 1 parameter, 2 given in %s on line %d +Warning: function_exists() expects at most 2 parameters, 3 given in %s on line %d NULL Too few arguments -Warning: function_exists() expects exactly 1 parameter, 0 given in %s on line %d +Warning: function_exists() expects at least 1 parameter, 0 given in %s on line %d NULL ===Done=== diff --git a/Zend/zend_builtin_functions.c b/Zend/zend_builtin_functions.c index 4c2030f42b703..11c841f729364 100644 --- a/Zend/zend_builtin_functions.c +++ b/Zend/zend_builtin_functions.c @@ -1366,8 +1366,8 @@ ZEND_FUNCTION(trait_exists) /* }}} */ -/* {{{ proto bool function_exists(string function_name) - Checks if the function exists */ +/* {{{ proto bool function_exists(string function_name [, boolean autoload = true]) + Checks if the function exists, optionally and by default invoking autoloaders */ ZEND_FUNCTION(function_exists) { char *name; From 2212f244ea68a93b2affaad3293ceb7ced4cbb37 Mon Sep 17 00:00:00 2001 From: krakjoe <joe.watkins@live.co.uk> Date: Sun, 22 Dec 2013 09:10:31 +0000 Subject: [PATCH 15/20] correct test --- Zend/tests/function_exists_error.phpt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Zend/tests/function_exists_error.phpt b/Zend/tests/function_exists_error.phpt index 1a696d47c171b..f3f2f6f89cbde 100644 --- a/Zend/tests/function_exists_error.phpt +++ b/Zend/tests/function_exists_error.phpt @@ -3,7 +3,7 @@ Test function_exists() function : error conditions --FILE-- <?php /* - * proto bool function_exists(string function_name) + * proto bool function_exists(string function_name [, boolean autoload = true]) * Function is implemented in Zend/zend_builtin_functions.c */ From e2d73a2aae005f5c4141ead8f3844fe2e7143271 Mon Sep 17 00:00:00 2001 From: krakjoe <joe.watkins@live.co.uk> Date: Sun, 22 Dec 2013 10:47:32 +0000 Subject: [PATCH 16/20] be compatible with phpdbg --- Zend/zend_autoload.c | 3 +++ Zend/zend_execute_API.c | 1 + 2 files changed, 4 insertions(+) diff --git a/Zend/zend_autoload.c b/Zend/zend_autoload.c index c2eaba07ddcda..0fff2bc51f353 100644 --- a/Zend/zend_autoload.c +++ b/Zend/zend_autoload.c @@ -71,10 +71,12 @@ int zend_autoload_call(const zval* name, long type TSRMLS_DC) ) ) { zend_call_method_with_1_params(NULL, NULL, &EG(autoload_legacy), ZEND_AUTOLOAD_FUNC_NAME, &retval, (zval*) name); + zend_exception_save(TSRMLS_C); if (zend_hash_exists(symbol_table, lc_name, lc_length + 1)) { if (retval) { zval_ptr_dtor(&retval); } + zend_exception_restore(TSRMLS_C); efree(lc_name); return SUCCESS; } @@ -82,6 +84,7 @@ int zend_autoload_call(const zval* name, long type TSRMLS_DC) zval_ptr_dtor(&retval); } } + zend_exception_restore(TSRMLS_C); efree(lc_name); return FAILURE; } diff --git a/Zend/zend_execute_API.c b/Zend/zend_execute_API.c index fc007c38eef52..9135da23283ae 100644 --- a/Zend/zend_execute_API.c +++ b/Zend/zend_execute_API.c @@ -346,6 +346,7 @@ void shutdown_executor(TSRMLS_D) /* {{{ */ FREE_HASHTABLE(EG(in_autoload)); EG(in_autoload) = NULL; } + EG(autoload_legacy) = NULL; } zend_end_try(); zend_shutdown_fpu(TSRMLS_C); From 2b68179ecf222ad8fb9fd8dc6396897c7f175b42 Mon Sep 17 00:00:00 2001 From: krakjoe <joe.watkins@live.co.uk> Date: Sun, 22 Dec 2013 11:54:42 +0000 Subject: [PATCH 17/20] fix zts build --- Zend/tests/bug61011.phpt | 2 +- Zend/zend_autoload.c | 57 ++++++++++++++++++----------------- Zend/zend_builtin_functions.c | 4 +-- Zend/zend_execute.h | 4 +-- ext/spl/php_spl.c | 4 +-- 5 files changed, 36 insertions(+), 35 deletions(-) diff --git a/Zend/tests/bug61011.phpt b/Zend/tests/bug61011.phpt index bce0e33209b3a..4efefc2ff5e21 100644 --- a/Zend/tests/bug61011.phpt +++ b/Zend/tests/bug61011.phpt @@ -5,7 +5,7 @@ Bug #61011 (Crash when an exception is thrown by __autoload accessing a static p function __autoload($name) { throw new Exception($name); } -try { +try { echo AAA::$a; //zend_fetch_var_address_helper } catch (Exception $e) { try { diff --git a/Zend/zend_autoload.c b/Zend/zend_autoload.c index 0fff2bc51f353..53f79bdf96b2d 100644 --- a/Zend/zend_autoload.c +++ b/Zend/zend_autoload.c @@ -63,38 +63,37 @@ int zend_autoload_call(const zval* name, long type TSRMLS_DC) lc_length = Z_STRLEN_P(name); lc_name = zend_str_tolower_dup(Z_STRVAL_P(name), lc_length); - if (EG(autoload_funcs) == NULL || EG(autoload_funcs)->nNumOfElements == 0) { - if (type == ZEND_AUTOLOAD_CLASS - && ( - EG(autoload_legacy) != NULL - || zend_lookup_function_ex(ZEND_AUTOLOAD_FUNC_NAME, sizeof(ZEND_AUTOLOAD_FUNC_NAME), NULL, 0, &EG(autoload_legacy) TSRMLS_CC) == SUCCESS - ) - ) { - zend_call_method_with_1_params(NULL, NULL, &EG(autoload_legacy), ZEND_AUTOLOAD_FUNC_NAME, &retval, (zval*) name); - zend_exception_save(TSRMLS_C); - if (zend_hash_exists(symbol_table, lc_name, lc_length + 1)) { + /* run legacy autoloader */ + { + zend_bool loaded = 0; + + if (EG(autoload_funcs) == NULL || EG(autoload_funcs)->nNumOfElements == 0) { + if (type == ZEND_AUTOLOAD_CLASS + && ( + EG(autoload_legacy) != NULL + || zend_lookup_function_ex(ZEND_AUTOLOAD_FUNC_NAME, sizeof(ZEND_AUTOLOAD_FUNC_NAME), NULL, 0, &EG(autoload_legacy) TSRMLS_CC) == SUCCESS + ) + ) { + zend_call_method_with_1_params(NULL, NULL, &EG(autoload_legacy), ZEND_AUTOLOAD_FUNC_NAME, &retval, (zval*) name); + loaded = zend_hash_exists( + symbol_table, lc_name, lc_length + 1); if (retval) { zval_ptr_dtor(&retval); } - zend_exception_restore(TSRMLS_C); - efree(lc_name); - return SUCCESS; - } - if (retval) { - zval_ptr_dtor(&retval); } + efree(lc_name); + + return (loaded) ? SUCCESS : FAILURE; } - zend_exception_restore(TSRMLS_C); - efree(lc_name); - return FAILURE; } - + if (EG(autoload_stack) == NULL) { ALLOC_HASHTABLE(EG(autoload_stack)); zend_hash_init(EG(autoload_stack), 0, NULL, NULL, 0); } - if (zend_hash_add(EG(autoload_stack), lc_name, lc_length, (void**)&dummy, sizeof(char), NULL) == FAILURE) { + if (zend_hash_add(EG(autoload_stack), lc_name, lc_length+1, (void**)&dummy, sizeof(char), NULL) == FAILURE) { + printf("failed to add to autoload stack\n"); efree(lc_name); return FAILURE; } @@ -107,7 +106,7 @@ int zend_autoload_call(const zval* name, long type TSRMLS_DC) zend_hash_get_current_data_ex(EG(autoload_funcs), (void **) &func_info, &function_pos); if (func_info->type & type) { func_info->fci.retval_ptr_ptr = &retval; - zend_fcall_info_argn(&func_info->fci, 2, &name, &ztype); + zend_fcall_info_argn(&func_info->fci TSRMLS_CC, 2, &name, &ztype); zend_call_function(&func_info->fci, &func_info->fcc TSRMLS_CC); zend_exception_save(TSRMLS_C); if (retval) { @@ -173,6 +172,8 @@ static char* zend_autoload_get_name_key(zend_fcall_info *fci, zend_fcall_info_ca default: return 0; } + + return 0; } static void zend_autoload_func_dtor(zend_autoload_func *func) { @@ -187,7 +188,7 @@ int zend_autoload_register(zend_autoload_func *func, zend_bool prepend TSRMLS_DC zend_bool do_free = 0; int lc_length, status = SUCCESS; - lc_name = zend_autoload_get_name_key(&func->fci, &func->fcc, &lc_length, &do_free); + lc_name = zend_autoload_get_name_key(&func->fci, &func->fcc, &lc_length, &do_free TSRMLS_CC); if (lc_name == 0) { zend_error_noreturn(E_ERROR, "Unknown Function Name Type Provided"); } @@ -221,11 +222,11 @@ int zend_autoload_unregister(zval *callable TSRMLS_DC) zend_bool do_free = 0; int lc_length; - if (zend_fcall_info_init(callable, 0, &fci, &fcc, NULL, NULL) == FAILURE) { + if (zend_fcall_info_init(callable, 0, &fci, &fcc, NULL, NULL TSRMLS_CC) == FAILURE) { return FAILURE; } - lc_name = zend_autoload_get_name_key(&fci, &fcc, &lc_length, &do_free); + lc_name = zend_autoload_get_name_key(&fci, &fcc, &lc_length, &do_free TSRMLS_CC); if (lc_name == 0) { return FAILURE; } @@ -245,13 +246,13 @@ ZEND_FUNCTION(autoload_register) zend_bool prepend = 0; long type = 0; - if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_DC, "z|lb", &callable, &type, &prepend) == FAILURE) { + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z|lb", &callable, &type, &prepend) == FAILURE) { return; } func = emalloc(sizeof(zend_autoload_func)); - if (zend_fcall_info_init(callable, 0, &func->fci, &func->fcc, NULL, NULL) == FAILURE) { + if (zend_fcall_info_init(callable, 0, &func->fci, &func->fcc, NULL, NULL TSRMLS_CC) == FAILURE) { efree(func); zend_error_noreturn(E_ERROR, "Expecting a valid callback"); } @@ -275,7 +276,7 @@ ZEND_FUNCTION(autoload_unregister) { zval *callable; - if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_DC, "z", &callable) == FAILURE) { + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z", &callable) == FAILURE) { return; } RETVAL_BOOL(zend_autoload_unregister(callable TSRMLS_CC) == SUCCESS); diff --git a/Zend/zend_builtin_functions.c b/Zend/zend_builtin_functions.c index 11c841f729364..0e0f729596f14 100644 --- a/Zend/zend_builtin_functions.c +++ b/Zend/zend_builtin_functions.c @@ -1390,7 +1390,7 @@ ZEND_FUNCTION(function_exists) name_len--; } - retval = (zend_lookup_function_ex(name, name_len+1, NULL, (int) autoload, &func) == SUCCESS); + retval = (zend_lookup_function_ex(name, name_len+1, NULL, (int) autoload, &func TSRMLS_CC) == SUCCESS); efree(lcname); @@ -1847,7 +1847,7 @@ ZEND_FUNCTION(create_function) if (retval==SUCCESS) { zend_function new_function, *func; - if (zend_lookup_function_ex(LAMBDA_TEMP_FUNCNAME, sizeof(LAMBDA_TEMP_FUNCNAME), NULL, 0, &func)==FAILURE) { + if (zend_lookup_function_ex(LAMBDA_TEMP_FUNCNAME, sizeof(LAMBDA_TEMP_FUNCNAME), NULL, 0, &func TSRMLS_CC)==FAILURE) { zend_error(E_ERROR, "Unexpected inconsistency in create_function()"); RETURN_FALSE; } diff --git a/Zend/zend_execute.h b/Zend/zend_execute.h index 7070125f1e065..19b56e72aa7d4 100644 --- a/Zend/zend_execute.h +++ b/Zend/zend_execute.h @@ -66,8 +66,8 @@ ZEND_API int zend_lookup_class_ex(const char *name, int name_length, const zend_ ZEND_API int zend_lookup_function(const char *name, int name_length, zend_function **fbc TSRMLS_DC); ZEND_API int zend_lookup_function_ex(const char *name, int name_length, const zend_literal *key, int use_autoload, zend_function **fbc TSRMLS_DC); -#define ZEND_LOOKUP_FUNCTION_BY_NAME(name, name_length, fbc) (zend_hash_find(EG(function_table), (name), (name_length) + 1, (void**) (fbc)) == SUCCESS || zend_lookup_function((name), (name_length), (fbc)) == SUCCESS) -#define ZEND_LOOKUP_FUNCTION_BY_LITERAL(name, name_length, literal, fbc) (zend_hash_quick_find(EG(function_table), (name), (name_length) + 1, Z_HASH_P(literal), (void**) (fbc)) == SUCCESS || zend_lookup_function_ex((name), (name_length), (zend_literal*) (literal), 1, (fbc)) == SUCCESS) +#define ZEND_LOOKUP_FUNCTION_BY_NAME(name, name_length, fbc) (zend_hash_find(EG(function_table), (name), (name_length) + 1, (void**) (fbc)) == SUCCESS || zend_lookup_function((name), (name_length), (fbc) TSRMLS_CC) == SUCCESS) +#define ZEND_LOOKUP_FUNCTION_BY_LITERAL(name, name_length, literal, fbc) (zend_hash_quick_find(EG(function_table), (name), (name_length) + 1, Z_HASH_P(literal), (void**) (fbc)) == SUCCESS || zend_lookup_function_ex((name), (name_length), (zend_literal*) (literal), 1, (fbc) TSRMLS_CC) == SUCCESS) ZEND_API int zend_eval_string(char *str, zval *retval_ptr, char *string_name TSRMLS_DC); ZEND_API int zend_eval_stringl(char *str, int str_len, zval *retval_ptr, char *string_name TSRMLS_DC); diff --git a/ext/spl/php_spl.c b/ext/spl/php_spl.c index 8bf633adaf57e..82017127c7d8a 100644 --- a/ext/spl/php_spl.c +++ b/ext/spl/php_spl.c @@ -405,7 +405,7 @@ PHP_FUNCTION(spl_autoload_call) if (EG(autoload_funcs) == NULL) { zend_call_method_with_1_params(NULL, NULL, NULL, "spl_autoload", NULL, class_name); } else { - zend_autoload_call(class_name, ZEND_AUTOLOAD_CLASS); + zend_autoload_call(class_name, ZEND_AUTOLOAD_CLASS TSRMLS_CC); } } /* }}} */ @@ -439,7 +439,7 @@ PHP_FUNCTION(spl_autoload_register) ZVAL_STRING(zcallable, "spl_autoload", 1); } - if (zend_fcall_info_init(zcallable, IS_CALLABLE_STRICT, &func->fci, &func->fcc, NULL, &error) == FAILURE) { + if (zend_fcall_info_init(zcallable, IS_CALLABLE_STRICT, &func->fci, &func->fcc, NULL, &error TSRMLS_CC) == FAILURE) { if (Z_TYPE_P(zcallable) == IS_ARRAY) { if (!func->fcc.object_ptr && func->fcc.function_handler && !(func->fcc.function_handler->common.fn_flags & ZEND_ACC_STATIC)) { if (do_throw) { From 92fe9491f5a1b6e7837ce31abd9e8c00e498156e Mon Sep 17 00:00:00 2001 From: krakjoe <joe.watkins@live.co.uk> Date: Sun, 22 Dec 2013 12:09:47 +0000 Subject: [PATCH 18/20] all tests pass --- Zend/zend_execute_API.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Zend/zend_execute_API.c b/Zend/zend_execute_API.c index 9135da23283ae..796f40be2c619 100644 --- a/Zend/zend_execute_API.c +++ b/Zend/zend_execute_API.c @@ -1186,6 +1186,8 @@ ZEND_API int zend_lookup_class_ex(const char *name, int name_length, const zend_ retval = SUCCESS; } zval_ptr_dtor(&class_name_ptr); + zend_hash_del(EG(in_autoload), lc_name, lc_length); + if (!key) { free_alloca(lc_free, use_heap); } From ed22ad919f4ab5948c85c8deebcdee185fccf348 Mon Sep 17 00:00:00 2001 From: krakjoe <joe.watkins@live.co.uk> Date: Sun, 22 Dec 2013 12:18:58 +0000 Subject: [PATCH 19/20] remove debug printing, add author line --- Zend/zend_autoload.c | 2 +- Zend/zend_autoload.h | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/Zend/zend_autoload.c b/Zend/zend_autoload.c index 53f79bdf96b2d..5226769099947 100644 --- a/Zend/zend_autoload.c +++ b/Zend/zend_autoload.c @@ -13,6 +13,7 @@ | license@zend.com so we can mail you a copy immediately. | +----------------------------------------------------------------------+ | Authors: Anthony Ferrara <ircmaxell@php.net> | + | Authors: Joe Watkins <krakjoe@php.net> | +----------------------------------------------------------------------+ */ @@ -93,7 +94,6 @@ int zend_autoload_call(const zval* name, long type TSRMLS_DC) } if (zend_hash_add(EG(autoload_stack), lc_name, lc_length+1, (void**)&dummy, sizeof(char), NULL) == FAILURE) { - printf("failed to add to autoload stack\n"); efree(lc_name); return FAILURE; } diff --git a/Zend/zend_autoload.h b/Zend/zend_autoload.h index 87d4bf54abe7d..de6134cda5ddc 100644 --- a/Zend/zend_autoload.h +++ b/Zend/zend_autoload.h @@ -13,6 +13,7 @@ | license@zend.com so we can mail you a copy immediately. | +----------------------------------------------------------------------+ | Authors: Anthony Ferrara <ircmaxell@php.net> | + | Authors: Joe Watkins <krakjoe@php.net> | +----------------------------------------------------------------------+ */ From c1b56c0885ab42604274629958af8050d5bf3342 Mon Sep 17 00:00:00 2001 From: krakjoe <joe.watkins@live.co.uk> Date: Sun, 22 Dec 2013 13:26:48 +0000 Subject: [PATCH 20/20] ... --- NEWS | 6 ------ 1 file changed, 6 deletions(-) diff --git a/NEWS b/NEWS index 51361215cb7bf..6bb92f7905aed 100644 --- a/NEWS +++ b/NEWS @@ -1,12 +1,6 @@ PHP NEWS ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||| -<<<<<<< HEAD ?? ??? 20??, PHP 5.7.0 -======= -<<<<<<< HEAD -?? ??? 20??, PHP 5.6.0 -======= -?? ??? 2013, PHP 5.5.8 - Core: . Disallowed JMP into a finally block. (Laruence)