diff --git a/Zend/zend.c b/Zend/zend.c index 2069b45..a386839 100644 --- a/Zend/zend.c +++ b/Zend/zend.c @@ -550,6 +550,10 @@ static void executor_globals_ctor(zend_executor_globals *executor_globals TSRMLS EG(current_module) = NULL; EG(exit_status) = 0; EG(active) = 0; + EG(lookup_function_hook) = NULL; + EG(lookup_class_hook) = NULL; + EG(defined_function_hook) = NULL; + EG(declared_class_hook) = NULL; } /* }}} */ diff --git a/Zend/zend_API.c b/Zend/zend_API.c index 3890769..ec968aa 100644 --- a/Zend/zend_API.c +++ b/Zend/zend_API.c @@ -2180,7 +2180,7 @@ ZEND_API zend_class_entry *zend_register_internal_class_ex(zend_class_entry *cla if (!parent_ce && parent_name) { zend_class_entry **pce; - if (zend_hash_find(CG(class_table), parent_name, strlen(parent_name)+1, (void **) &pce)==FAILURE) { + if (zend_find_class(CG(class_table), parent_name, strlen(parent_name)+1, &pce TSRMLS_CC)==FAILURE) { return NULL; } else { parent_ce = *pce; @@ -2228,14 +2228,20 @@ ZEND_API zend_class_entry *zend_register_internal_interface(zend_class_entry *or ZEND_API int zend_register_class_alias_ex(const char *name, int name_len, zend_class_entry *ce TSRMLS_DC) /* {{{ */ { char *lcname = zend_str_tolower_dup(name, name_len); - int ret; + ulong hash = zend_inline_hash_func(lcname, name_len+1); + zend_class_entry **pce; - ret = zend_hash_add(CG(class_table), lcname, name_len+1, &ce, sizeof(zend_class_entry *), NULL); - efree(lcname); - if (ret == SUCCESS) { - ce->refcount++; + if((EG(lookup_class_hook) && + /* Check if we have a same-name class already exsiting in our hook, then fail as we would normally below. + * This could happen if we have two classes with the same name, and one of them is being bound at run-time */ + EG(lookup_class_hook)(lcname, name_len+1, hash, &pce) == SUCCESS) || + zend_hash_quick_add(CG(class_table), lcname, name_len+1, hash, &ce, sizeof(zend_class_entry *), NULL) == FAILURE) { + efree(lcname); + return FAILURE; } - return ret; + efree(lcname); + ce->refcount++; + return SUCCESS; } /* }}} */ @@ -2412,7 +2418,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_find_function(EG(function_table), lmname, mlen+1, &fcc->function_handler TSRMLS_CC) == SUCCESS) { efree(lmname); return 1; } @@ -3552,6 +3558,86 @@ ZEND_API void zend_restore_error_handling(zend_error_handling *saved TSRMLS_DC) } /* }}} */ +ZEND_API int zend_quick_find_function(HashTable *function_table, const char *name, int len, zend_ulong h, zend_function **fe TSRMLS_DC) /* {{{ */ +{ + if (zend_hash_quick_find(function_table, name, len, h, (void**)fe) == SUCCESS) { + return SUCCESS; + } else if (EG(lookup_function_hook)) { + return EG(lookup_function_hook)(name, len, h, fe); + } + return FAILURE; +} +/* }}} */ + +ZEND_API int zend_find_function(HashTable *function_table, const char *name, int len, zend_function **fe TSRMLS_DC) /* {{{ */ +{ + ulong h = zend_inline_hash_func(name, len); + + if (zend_hash_quick_find(function_table, name, len, h, (void**)fe) == SUCCESS) { + return SUCCESS; + } else if (EG(lookup_function_hook)) { + return EG(lookup_function_hook)(name, len, h, fe); + } + return FAILURE; +} +/* }}} */ + +ZEND_API int zend_quick_find_class(HashTable *class_table, const char *name, int len, zend_ulong h, zend_class_entry ***ce TSRMLS_DC) /* {{{ */ +{ + if (zend_hash_quick_find(class_table, name, len, h, (void**)ce) == SUCCESS) { + return SUCCESS; + } else if (EG(lookup_class_hook)) { + return EG(lookup_class_hook)(name, len, h, ce); + } + return FAILURE; +} +/* }}} */ + +ZEND_API int zend_find_class(HashTable *class_table, const char *name, int len, zend_class_entry ***ce TSRMLS_DC) /* {{{ */ +{ + ulong h = zend_inline_hash_func(name, len); + + if (zend_hash_quick_find(class_table, name, len, h, (void**)ce) == SUCCESS) { + return SUCCESS; + } else if (EG(lookup_class_hook)) { + return EG(lookup_class_hook)(name, len, h, ce); + } + return FAILURE; +} +/* }}} */ + +ZEND_API zend_lookup_function_hook_t zend_set_lookup_function_hook(zend_lookup_function_hook_t new_hook TSRMLS_DC) { /* {{{ */ + zend_lookup_function_hook_t old_hook; + old_hook = EG(lookup_function_hook); + EG(lookup_function_hook) = new_hook; + return old_hook; +} +/* }}} */ + +ZEND_API zend_defined_function_hook_t zend_set_defined_function_hook(zend_defined_function_hook_t new_hook TSRMLS_DC) { /* {{{ */ + zend_defined_function_hook_t old_hook; + old_hook = EG(defined_function_hook); + EG(defined_function_hook) = new_hook; + return old_hook; +} +/* }}} */ + +ZEND_API zend_lookup_class_hook_t zend_set_lookup_class_hook(zend_lookup_class_hook_t new_hook TSRMLS_DC) { /* {{{ */ + zend_lookup_class_hook_t old_hook; + old_hook = EG(lookup_class_hook); + EG(lookup_class_hook) = new_hook; + return old_hook; +} +/* }}} */ + +ZEND_API zend_declared_class_hook_t zend_set_declared_class_hook(zend_declared_class_hook_t new_hook TSRMLS_DC) { /* {{{ */ + zend_declared_class_hook_t old_hook; + old_hook = EG(declared_class_hook); + EG(declared_class_hook) = new_hook; + return old_hook; +} +/* }}} */ + /* * Local variables: * tab-width: 4 diff --git a/Zend/zend_API.h b/Zend/zend_API.h index c286f2d..a924eea 100644 --- a/Zend/zend_API.h +++ b/Zend/zend_API.h @@ -322,6 +322,17 @@ ZEND_API zval *zend_read_static_property(zend_class_entry *scope, char *name, in ZEND_API zend_class_entry *zend_get_class_entry(const zval *zobject TSRMLS_DC); ZEND_API int zend_get_object_classname(const zval *object, char **class_name, zend_uint *class_name_len TSRMLS_DC); + +ZEND_API int zend_quick_find_function(HashTable *function_table, const char *name, int len, zend_ulong h, zend_function **fe TSRMLS_DC); +ZEND_API int zend_find_function(HashTable *function_table, const char *name, int len, zend_function **fe TSRMLS_DC); +ZEND_API int zend_quick_find_class(HashTable *class_table, const char *name, int len, zend_ulong h, zend_class_entry ***ce TSRMLS_DC); +ZEND_API int zend_find_class(HashTable *class_table, const char *name, int len, zend_class_entry ***ce TSRMLS_DC); + +ZEND_API zend_lookup_function_hook_t zend_set_lookup_function_hook(zend_lookup_function_hook_t new_hook TSRMLS_DC); +ZEND_API zend_defined_function_hook_t zend_set_defined_function_hook(zend_defined_function_hook_t new_hook TSRMLS_DC); +ZEND_API zend_lookup_class_hook_t zend_set_lookup_class_hook(zend_lookup_class_hook_t new_hook TSRMLS_DC); +ZEND_API zend_declared_class_hook_t zend_set_declared_class_hook(zend_declared_class_hook_t new_hook TSRMLS_DC); + ZEND_API char *zend_get_type_by_const(int type); #define getThis() (this_ptr) diff --git a/Zend/zend_builtin_functions.c b/Zend/zend_builtin_functions.c index 2c5f42b..f0fcf03 100644 --- a/Zend/zend_builtin_functions.c +++ b/Zend/zend_builtin_functions.c @@ -1199,7 +1199,7 @@ ZEND_FUNCTION(class_exists) len--; } - found = zend_hash_find(EG(class_table), name, len+1, (void **) &ce); + found = zend_find_class(EG(class_table), name, len+1, &ce TSRMLS_CC); free_alloca(lc_name, use_heap); RETURN_BOOL(found == SUCCESS && !((*ce)->ce_flags & ZEND_ACC_INTERFACE)); } @@ -1242,7 +1242,7 @@ ZEND_FUNCTION(interface_exists) len--; } - found = zend_hash_find(EG(class_table), name, len+1, (void **) &ce); + found = zend_find_class(EG(class_table), name, len+1, &ce TSRMLS_CC); free_alloca(lc_name, use_heap); RETURN_BOOL(found == SUCCESS && (*ce)->ce_flags & ZEND_ACC_INTERFACE); } @@ -1279,7 +1279,7 @@ ZEND_FUNCTION(function_exists) name_len--; } - retval = (zend_hash_find(EG(function_table), name, name_len+1, (void **)&func) == SUCCESS); + retval = (zend_find_function(EG(function_table), name, name_len+1, &func TSRMLS_CC) == SUCCESS); efree(lcname); @@ -1315,7 +1315,7 @@ ZEND_FUNCTION(class_alias) lc_name = do_alloca(class_name_len + 1, use_heap); zend_str_tolower_copy(lc_name, class_name, class_name_len); - found = zend_hash_find(EG(class_table), lc_name, class_name_len+1, (void **) &ce); + found = zend_find_class(EG(class_table), lc_name, class_name_len+1, &ce TSRMLS_CC); free_alloca(lc_name, use_heap); } else { found = zend_lookup_class(class_name, class_name_len, &ce TSRMLS_CC); @@ -1579,6 +1579,7 @@ ZEND_FUNCTION(get_declared_classes) array_init(return_value); zend_hash_apply_with_arguments(EG(class_table) TSRMLS_CC, (apply_func_args_t) copy_class_or_interface_name, 3, return_value, mask, comply); + if (EG(declared_class_hook)) EG(declared_class_hook)(return_value, mask, comply); } /* }}} */ @@ -1595,6 +1596,7 @@ ZEND_FUNCTION(get_declared_interfaces) array_init(return_value); zend_hash_apply_with_arguments(EG(class_table) TSRMLS_CC, (apply_func_args_t) copy_class_or_interface_name, 3, return_value, mask, comply); + if (EG(declared_class_hook)) EG(declared_class_hook)(return_value, mask, comply); } /* }}} */ @@ -1637,6 +1639,7 @@ ZEND_FUNCTION(get_defined_functions) array_init(return_value); zend_hash_apply_with_arguments(EG(function_table) TSRMLS_CC, (apply_func_args_t) copy_function_name, 2, internal, user); + if (EG(defined_function_hook)) EG(defined_function_hook)(internal, user); if (zend_hash_add(Z_ARRVAL_P(return_value), "internal", sizeof("internal"), (void **)&internal, sizeof(zval *), NULL) == FAILURE) { zval_ptr_dtor(&internal); @@ -1696,7 +1699,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_find_function(EG(function_table), LAMBDA_TEMP_FUNCNAME, sizeof(LAMBDA_TEMP_FUNCNAME), &func TSRMLS_CC)==FAILURE) { zend_error(E_ERROR, "Unexpected inconsistency in create_function()"); RETURN_FALSE; } diff --git a/Zend/zend_compile.c b/Zend/zend_compile.c index ae14878..26fab22 100644 --- a/Zend/zend_compile.c +++ b/Zend/zend_compile.c @@ -1556,7 +1556,7 @@ int zend_do_begin_function_call(znode *function_name, zend_bool check_namespace } lcname = zend_str_tolower_dup(function_name->u.constant.value.str.val, function_name->u.constant.value.str.len); - if ((zend_hash_find(CG(function_table), lcname, function_name->u.constant.value.str.len+1, (void **) &function)==FAILURE) || + if ((zend_hash_find(CG(function_table), lcname, function_name->u.constant.value.str.len+1, (void**)&function)==FAILURE) || ((CG(compiler_options) & ZEND_COMPILE_IGNORE_INTERNAL_FUNCTIONS) && (function->type == ZEND_INTERNAL_FUNCTION))) { zend_do_begin_dynamic_function_call(function_name, 0 TSRMLS_CC); @@ -2890,17 +2890,24 @@ ZEND_API void zend_do_implement_interface(zend_class_entry *ce, zend_class_entry ZEND_API int do_bind_function(zend_op *opline, HashTable *function_table, zend_bool compile_time) { zend_function *function; + ulong hash; + TSRMLS_FETCH(); if (opline->opcode != ZEND_DECLARE_FUNCTION) { zend_error(E_COMPILE_ERROR, "Internal compiler error. Please report!"); } zend_hash_find(function_table, opline->op1.u.constant.value.str.val, opline->op1.u.constant.value.str.len, (void *) &function); - if (zend_hash_add(function_table, opline->op2.u.constant.value.str.val, opline->op2.u.constant.value.str.len+1, function, sizeof(zend_function), NULL)==FAILURE) { + hash = zend_inline_hash_func(opline->op2.u.constant.value.str.val, opline->op2.u.constant.value.str.len+1); + if((EG(lookup_function_hook) && + /* Check if we have a same-name function already exsiting in our hook, then fail as we would normally below. + * This could happen if we have two functions with the same name, and one of them is being bound at run-time */ + EG(lookup_function_hook)(opline->op2.u.constant.value.str.val, opline->op2.u.constant.value.str.len+1, hash, &function) == SUCCESS) || + zend_hash_quick_add(function_table, opline->op2.u.constant.value.str.val, opline->op2.u.constant.value.str.len+1, hash, function, sizeof(zend_function), NULL)==FAILURE) { int error_level = compile_time ? E_COMPILE_ERROR : E_ERROR; zend_function *function; - if (zend_hash_find(function_table, opline->op2.u.constant.value.str.val, opline->op2.u.constant.value.str.len+1, (void *) &function)==SUCCESS + if (zend_hash_quick_find(function_table, opline->op2.u.constant.value.str.val, opline->op2.u.constant.value.str.len+1, hash, (void *) &function)==SUCCESS && function->type==ZEND_USER_FUNCTION && ((zend_op_array *) function)->last>0) { zend_error(error_level, "Cannot redeclare %s() (previously declared in %s:%d)", @@ -2922,15 +2929,20 @@ ZEND_API int do_bind_function(zend_op *opline, HashTable *function_table, zend_b ZEND_API zend_class_entry *do_bind_class(const zend_op *opline, HashTable *class_table, zend_bool compile_time TSRMLS_DC) { zend_class_entry *ce, **pce; + ulong hash = zend_inline_hash_func(opline->op1.u.constant.value.str.val, opline->op1.u.constant.value.str.len); - if (zend_hash_find(class_table, opline->op1.u.constant.value.str.val, opline->op1.u.constant.value.str.len, (void **) &pce)==FAILURE) { + if (zend_find_class(class_table, opline->op1.u.constant.value.str.val, opline->op1.u.constant.value.str.len, &pce TSRMLS_CC)==FAILURE) { zend_error(E_COMPILE_ERROR, "Internal Zend error - Missing class information for %s", opline->op1.u.constant.value.str.val); return NULL; - } else { - ce = *pce; } + ce = *pce; ce->refcount++; - if (zend_hash_add(class_table, opline->op2.u.constant.value.str.val, opline->op2.u.constant.value.str.len+1, &ce, sizeof(zend_class_entry *), NULL)==FAILURE) { + hash = zend_inline_hash_func(opline->op2.u.constant.value.str.val, opline->op2.u.constant.value.str.len+1); + if((EG(lookup_class_hook) && + /* Check if we have a same-name class already exsiting in our hook, then fail as we would normally below. + * This could happen if we have two classes with the same name, and one of them is being bound at run-time */ + EG(lookup_class_hook)(opline->op2.u.constant.value.str.val, opline->op2.u.constant.value.str.len+1, hash, &pce) == SUCCESS) || + zend_hash_quick_add(class_table, opline->op2.u.constant.value.str.val, opline->op2.u.constant.value.str.len+1, hash, &ce, sizeof(zend_class_entry *), NULL)==FAILURE) { ce->refcount--; if (!compile_time) { /* If we're in compile time, in practice, it's quite possible @@ -2953,11 +2965,9 @@ ZEND_API zend_class_entry *do_bind_class(const zend_op *opline, HashTable *class ZEND_API zend_class_entry *do_bind_inherited_class(const zend_op *opline, HashTable *class_table, zend_class_entry *parent_ce, zend_bool compile_time TSRMLS_DC) { zend_class_entry *ce, **pce; - int found_ce; - - found_ce = zend_hash_find(class_table, opline->op1.u.constant.value.str.val, opline->op1.u.constant.value.str.len, (void **) &pce); + ulong hash; - if (found_ce == FAILURE) { + if (zend_find_class(class_table, opline->op1.u.constant.value.str.val, opline->op1.u.constant.value.str.len, &pce TSRMLS_CC) == FAILURE) { if (!compile_time) { /* If we're in compile time, in practice, it's quite possible * that we'll never reach this class declaration at runtime, @@ -2980,7 +2990,12 @@ ZEND_API zend_class_entry *do_bind_inherited_class(const zend_op *opline, HashTa ce->refcount++; /* Register the derived class */ - if (zend_hash_add(class_table, opline->op2.u.constant.value.str.val, opline->op2.u.constant.value.str.len+1, pce, sizeof(zend_class_entry *), NULL)==FAILURE) { + hash = zend_inline_hash_func(opline->op2.u.constant.value.str.val, opline->op2.u.constant.value.str.len+1); + if((EG(lookup_class_hook) && + /* Check if we have a same-name class already exsiting in our hook, then fail as we would normally below. + * This could happen if we have two classes with the same name, and one of them is being bound at run-time */ + EG(lookup_class_hook)(opline->op2.u.constant.value.str.val, opline->op2.u.constant.value.str.len+1, hash, &pce) == SUCCESS) || + zend_hash_quick_add(class_table, opline->op2.u.constant.value.str.val, opline->op2.u.constant.value.str.len+1, hash, pce, sizeof(zend_class_entry *), NULL)==FAILURE) { zend_error(E_COMPILE_ERROR, "Cannot redeclare class %s", ce->name); ce->refcount--; zend_hash_destroy(&ce->function_table); @@ -3023,9 +3038,9 @@ void zend_do_early_binding(TSRMLS_D) zend_class_entry **pce; if ((zend_lookup_class(Z_STRVAL_P(parent_name), Z_STRLEN_P(parent_name), &pce TSRMLS_CC) == FAILURE) || - ((CG(compiler_options) & ZEND_COMPILE_IGNORE_INTERNAL_CLASSES) && - ((*pce)->type == ZEND_INTERNAL_CLASS))) { - if (CG(compiler_options) & ZEND_COMPILE_DELAYED_BINDING) { + ((CG(compiler_options) & ZEND_COMPILE_IGNORE_INTERNAL_CLASSES) && + ((*pce)->type == ZEND_INTERNAL_CLASS))) { + if (CG(compiler_options) & ZEND_COMPILE_DELAYED_BINDING) { zend_uint *opline_num = &CG(active_op_array)->early_binding; while (*opline_num != -1) { @@ -5164,11 +5179,12 @@ void zend_do_use(znode *ns_name, znode *new_name, int is_global TSRMLS_DC) /* {{ if (CG(current_namespace)) { /* Prefix import name with current namespace name to avoid conflicts with classes */ char *ns_name = emalloc(Z_STRLEN_P(CG(current_namespace)) + 1 + Z_STRLEN_P(name) + 1); + zend_class_entry **dummy; zend_str_tolower_copy(ns_name, Z_STRVAL_P(CG(current_namespace)), Z_STRLEN_P(CG(current_namespace))); ns_name[Z_STRLEN_P(CG(current_namespace))] = '\\'; memcpy(ns_name+Z_STRLEN_P(CG(current_namespace))+1, lcname, Z_STRLEN_P(name)+1); - if (zend_hash_exists(CG(class_table), ns_name, Z_STRLEN_P(CG(current_namespace)) + 1 + Z_STRLEN_P(name)+1)) { + if (zend_find_class(CG(class_table), ns_name, Z_STRLEN_P(CG(current_namespace)) + 1 + Z_STRLEN_P(name)+1, &dummy TSRMLS_CC) == SUCCESS) { char *tmp = zend_str_tolower_dup(Z_STRVAL_P(ns), Z_STRLEN_P(ns)); if (Z_STRLEN_P(ns) != Z_STRLEN_P(CG(current_namespace)) + 1 + Z_STRLEN_P(name) || @@ -5178,7 +5194,7 @@ void zend_do_use(znode *ns_name, znode *new_name, int is_global TSRMLS_DC) /* {{ efree(tmp); } efree(ns_name); - } else if (zend_hash_find(CG(class_table), lcname, Z_STRLEN_P(name)+1, (void**)&pce) == SUCCESS && + } else if (zend_find_class(CG(class_table), lcname, Z_STRLEN_P(name)+1, &pce TSRMLS_CC) == SUCCESS && (*pce)->type == ZEND_USER_CLASS && (*pce)->filename == CG(compiled_filename)) { char *tmp = zend_str_tolower_dup(Z_STRVAL_P(ns), Z_STRLEN_P(ns)); diff --git a/Zend/zend_execute_API.c b/Zend/zend_execute_API.c index ce5f1b3..d3ef103 100644 --- a/Zend/zend_execute_API.c +++ b/Zend/zend_execute_API.c @@ -1014,6 +1014,7 @@ ZEND_API int zend_lookup_class_ex(const char *name, int name_length, int use_aut zend_fcall_info fcall_info; zend_fcall_info_cache fcall_cache; char dummy = 1; + ulong hash; ALLOCA_FLAG(use_heap) if (name == NULL || !name_length) { @@ -1029,7 +1030,8 @@ ZEND_API int zend_lookup_class_ex(const char *name, int name_length, int use_aut lc_length -= 1; } - if (zend_hash_find(EG(class_table), lc_name, lc_length, (void **) ce) == SUCCESS) { + hash = zend_inline_hash_func(lc_name, lc_length); + if (zend_quick_find_class(EG(class_table), lc_name, lc_length, hash, ce TSRMLS_CC) == SUCCESS) { free_alloca(lc_free, use_heap); return SUCCESS; } @@ -1047,7 +1049,7 @@ ZEND_API int zend_lookup_class_ex(const char *name, int name_length, int use_aut zend_hash_init(EG(in_autoload), 0, NULL, NULL, 0); } - if (zend_hash_add(EG(in_autoload), lc_name, lc_length, (void**)&dummy, sizeof(char), NULL) == FAILURE) { + if (zend_hash_quick_add(EG(in_autoload), lc_name, lc_length, hash, (void**)&dummy, sizeof(char), NULL) == FAILURE) { free_alloca(lc_free, use_heap); return FAILURE; } @@ -1095,8 +1097,9 @@ ZEND_API int zend_lookup_class_ex(const char *name, int name_length, int use_aut return FAILURE; } - retval = zend_hash_find(EG(class_table), lc_name, lc_length, (void **) ce); + retval = zend_quick_find_class(EG(class_table), lc_name, lc_length, hash, ce TSRMLS_CC); free_alloca(lc_free, use_heap); + return retval; } /* }}} */ diff --git a/Zend/zend_globals.h b/Zend/zend_globals.h index 6e27f28..c08ec27 100644 --- a/Zend/zend_globals.h +++ b/Zend/zend_globals.h @@ -160,6 +160,10 @@ struct _zend_compiler_globals { #endif }; +typedef int (*zend_lookup_function_hook_t)(const char *name, int len, ulong hash, zend_function** fe_pp); +typedef int (*zend_lookup_class_hook_t)(const char* name, int len, ulong hash, zend_class_entry*** ce_pp); +typedef int (*zend_defined_function_hook_t)(zval *internal, zval *user); +typedef int (*zend_declared_class_hook_t)(zval *classes, zend_uint mask, zend_uint comply); struct _zend_executor_globals { zval **return_value_ptr_ptr; @@ -254,6 +258,11 @@ struct _zend_executor_globals { zend_bool active; + zend_lookup_function_hook_t lookup_function_hook; + zend_defined_function_hook_t defined_function_hook; + zend_lookup_class_hook_t lookup_class_hook; + zend_declared_class_hook_t declared_class_hook; + void *reserved[ZEND_MAX_RESERVED_RESOURCES]; }; diff --git a/Zend/zend_vm_def.h b/Zend/zend_vm_def.h index 5e52fe9..98ec122 100644 --- a/Zend/zend_vm_def.h +++ b/Zend/zend_vm_def.h @@ -2061,7 +2061,7 @@ ZEND_VM_HANDLER(59, ZEND_INIT_FCALL_BY_NAME, ANY, CONST|TMP|VAR|CV) zend_ptr_stack_3_push(&EG(arg_types_stack), EX(fbc), EX(object), EX(called_scope)); if (OP2_TYPE == IS_CONST) { - if (zend_hash_quick_find(EG(function_table), Z_STRVAL(opline->op1.u.constant), Z_STRLEN(opline->op1.u.constant)+1, opline->extended_value, (void **) &EX(fbc)) == FAILURE) { + if (zend_quick_find_function(EG(function_table), Z_STRVAL(opline->op1.u.constant), Z_STRLEN(opline->op1.u.constant)+1, opline->extended_value, &EX(fbc) TSRMLS_CC) == FAILURE) { zend_error_noreturn(E_ERROR, "Call to undefined function %s()", Z_STRVAL(opline->op2.u.constant)); } } else { @@ -2089,7 +2089,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 (zend_hash_find(EG(function_table), lcname, function_name_strlen+1, (void **) &EX(fbc)) == FAILURE) { + if (zend_find_function(EG(function_table), lcname, function_name_strlen+1, &EX(fbc) TSRMLS_CC) == FAILURE) { zend_error_noreturn(E_ERROR, "Call to undefined function %s()", function_name_strval); } efree(lcname); @@ -2408,7 +2408,7 @@ ZEND_VM_HANDLER(60, ZEND_DO_FCALL, CONST, ANY) zend_ptr_stack_3_push(&EG(arg_types_stack), EX(fbc), EX(object), EX(called_scope)); - if (zend_hash_quick_find(EG(function_table), fname->value.str.val, fname->value.str.len+1, Z_LVAL(opline->op2.u.constant), (void **) &EX(function_state).function)==FAILURE) { + if (zend_quick_find_function(EG(function_table), fname->value.str.val, fname->value.str.len+1, Z_LVAL(opline->op2.u.constant), &EX(function_state).function TSRMLS_CC)==FAILURE) { zend_error_noreturn(E_ERROR, "Call to undefined function %s()", fname->value.str.val); } EX(object) = NULL; diff --git a/Zend/zend_vm_execute.h b/Zend/zend_vm_execute.h index 2b4f9e7..33d900d 100644 --- a/Zend/zend_vm_execute.h +++ b/Zend/zend_vm_execute.h @@ -741,7 +741,7 @@ static int ZEND_FASTCALL ZEND_INIT_FCALL_BY_NAME_SPEC_CONST_HANDLER(ZEND_OPCODE zend_ptr_stack_3_push(&EG(arg_types_stack), EX(fbc), EX(object), EX(called_scope)); if (IS_CONST == IS_CONST) { - if (zend_hash_quick_find(EG(function_table), Z_STRVAL(opline->op1.u.constant), Z_STRLEN(opline->op1.u.constant)+1, opline->extended_value, (void **) &EX(fbc)) == FAILURE) { + if (zend_quick_find_function(EG(function_table), Z_STRVAL(opline->op1.u.constant), Z_STRLEN(opline->op1.u.constant)+1, opline->extended_value, &EX(fbc) TSRMLS_CC) == FAILURE) { zend_error_noreturn(E_ERROR, "Call to undefined function %s()", Z_STRVAL(opline->op2.u.constant)); } } else { @@ -769,7 +769,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 (zend_hash_find(EG(function_table), lcname, function_name_strlen+1, (void **) &EX(fbc)) == FAILURE) { + if (zend_find_function(EG(function_table), lcname, function_name_strlen+1, &EX(fbc) TSRMLS_CC) == FAILURE) { zend_error_noreturn(E_ERROR, "Call to undefined function %s()", function_name_strval); } efree(lcname); @@ -938,7 +938,7 @@ static int ZEND_FASTCALL ZEND_INIT_FCALL_BY_NAME_SPEC_TMP_HANDLER(ZEND_OPCODE_H zend_ptr_stack_3_push(&EG(arg_types_stack), EX(fbc), EX(object), EX(called_scope)); if (IS_TMP_VAR == IS_CONST) { - if (zend_hash_quick_find(EG(function_table), Z_STRVAL(opline->op1.u.constant), Z_STRLEN(opline->op1.u.constant)+1, opline->extended_value, (void **) &EX(fbc)) == FAILURE) { + if (zend_quick_find_function(EG(function_table), Z_STRVAL(opline->op1.u.constant), Z_STRLEN(opline->op1.u.constant)+1, opline->extended_value, &EX(fbc) TSRMLS_CC) == FAILURE) { zend_error_noreturn(E_ERROR, "Call to undefined function %s()", Z_STRVAL(opline->op2.u.constant)); } } else { @@ -966,7 +966,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 (zend_hash_find(EG(function_table), lcname, function_name_strlen+1, (void **) &EX(fbc)) == FAILURE) { + if (zend_find_function(EG(function_table), lcname, function_name_strlen+1, &EX(fbc) TSRMLS_CC) == FAILURE) { zend_error_noreturn(E_ERROR, "Call to undefined function %s()", function_name_strval); } efree(lcname); @@ -1043,7 +1043,7 @@ static int ZEND_FASTCALL ZEND_INIT_FCALL_BY_NAME_SPEC_VAR_HANDLER(ZEND_OPCODE_H zend_ptr_stack_3_push(&EG(arg_types_stack), EX(fbc), EX(object), EX(called_scope)); if (IS_VAR == IS_CONST) { - if (zend_hash_quick_find(EG(function_table), Z_STRVAL(opline->op1.u.constant), Z_STRLEN(opline->op1.u.constant)+1, opline->extended_value, (void **) &EX(fbc)) == FAILURE) { + if (zend_quick_find_function(EG(function_table), Z_STRVAL(opline->op1.u.constant), Z_STRLEN(opline->op1.u.constant)+1, opline->extended_value, &EX(fbc) TSRMLS_CC) == FAILURE) { zend_error_noreturn(E_ERROR, "Call to undefined function %s()", Z_STRVAL(opline->op2.u.constant)); } } else { @@ -1071,7 +1071,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 (zend_hash_find(EG(function_table), lcname, function_name_strlen+1, (void **) &EX(fbc)) == FAILURE) { + if (zend_find_function(EG(function_table), lcname, function_name_strlen+1, &EX(fbc) TSRMLS_CC) == FAILURE) { zend_error_noreturn(E_ERROR, "Call to undefined function %s()", function_name_strval); } efree(lcname); @@ -1176,7 +1176,7 @@ static int ZEND_FASTCALL ZEND_INIT_FCALL_BY_NAME_SPEC_CV_HANDLER(ZEND_OPCODE_HA zend_ptr_stack_3_push(&EG(arg_types_stack), EX(fbc), EX(object), EX(called_scope)); if (IS_CV == IS_CONST) { - if (zend_hash_quick_find(EG(function_table), Z_STRVAL(opline->op1.u.constant), Z_STRLEN(opline->op1.u.constant)+1, opline->extended_value, (void **) &EX(fbc)) == FAILURE) { + if (zend_quick_find_function(EG(function_table), Z_STRVAL(opline->op1.u.constant), Z_STRLEN(opline->op1.u.constant)+1, opline->extended_value, &EX(fbc) TSRMLS_CC) == FAILURE) { zend_error_noreturn(E_ERROR, "Call to undefined function %s()", Z_STRVAL(opline->op2.u.constant)); } } else { @@ -1204,7 +1204,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 (zend_hash_find(EG(function_table), lcname, function_name_strlen+1, (void **) &EX(fbc)) == FAILURE) { + if (zend_find_function(EG(function_table), lcname, function_name_strlen+1, &EX(fbc) TSRMLS_CC) == FAILURE) { zend_error_noreturn(E_ERROR, "Call to undefined function %s()", function_name_strval); } efree(lcname); @@ -1556,7 +1556,7 @@ static int ZEND_FASTCALL ZEND_DO_FCALL_SPEC_CONST_HANDLER(ZEND_OPCODE_HANDLER_A zend_ptr_stack_3_push(&EG(arg_types_stack), EX(fbc), EX(object), EX(called_scope)); - if (zend_hash_quick_find(EG(function_table), fname->value.str.val, fname->value.str.len+1, Z_LVAL(opline->op2.u.constant), (void **) &EX(function_state).function)==FAILURE) { + if (zend_quick_find_function(EG(function_table), fname->value.str.val, fname->value.str.len+1, Z_LVAL(opline->op2.u.constant), &EX(function_state).function TSRMLS_CC)==FAILURE) { zend_error_noreturn(E_ERROR, "Call to undefined function %s()", fname->value.str.val); } EX(object) = NULL; diff --git a/ext/pdo/pdo_stmt.c b/ext/pdo/pdo_stmt.c index e455123..2e58c01 100755 --- a/ext/pdo/pdo_stmt.c +++ b/ext/pdo/pdo_stmt.c @@ -856,10 +856,18 @@ static int make_callable_ex(pdo_stmt_t *stmt, zval *callable, zend_fcall_info * } zend_str_tolower_copy(fname, fname, strlen(fname)); - fci->function_table = ce ? &ce->function_table : EG(function_table); - if (zend_hash_find(fci->function_table, fname, strlen(fname)+1, (void **)&function_handler) == FAILURE) { - pdo_raise_impl_error(stmt->dbh, stmt, "HY000", "user-supplied function does not exist" TSRMLS_CC); - return 0; + if (ce) { + fci->function_table = &ce->function_table; + if (zend_hash_find(fci->function_table, fname, strlen(fname)+1, (void **)&function_handler) == FAILURE) { + pdo_raise_impl_error(stmt->dbh, stmt, "HY000", "user-supplied function does not exist" TSRMLS_CC); + return 0; + } + } else { + fci->function_table = EG(function_table); + if (zend_find_function(fci->function_table, fname, strlen(fname)+1, &function_handler TSRMLS_CC) == FAILURE) { + pdo_raise_impl_error(stmt->dbh, stmt, "HY000", "user-supplied function does not exist" TSRMLS_CC); + return 0; + } } efree(cname ? cname : fname); diff --git a/ext/reflection/php_reflection.c b/ext/reflection/php_reflection.c index af2139b..68d6800 100644 --- a/ext/reflection/php_reflection.c +++ b/ext/reflection/php_reflection.c @@ -1076,7 +1076,7 @@ static void _extension_string(string *str, zend_module_entry *module, char *inde /* Is there a better way of doing this? */ while (func->fname) { - if (zend_hash_find(EG(function_table), func->fname, strlen(func->fname) + 1, (void**) &fptr) == FAILURE) { + if (zend_find_function(EG(function_table), func->fname, strlen(func->fname) + 1, &fptr TSRMLS_CC) == FAILURE) { zend_error(E_WARNING, "Internal error: Cannot find extension function %s in global function table", func->fname); func++; continue; @@ -1513,7 +1513,7 @@ ZEND_METHOD(reflection_function, __construct) Z_ADDREF_P(closure); } else if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &name_str, &name_len) == SUCCESS) { lcname = zend_str_tolower_dup(name_str, name_len); - if (zend_hash_find(EG(function_table), lcname, name_len + 1, (void **)&fptr) == FAILURE) { + if (zend_find_function(EG(function_table), lcname, name_len + 1, &fptr TSRMLS_CC) == FAILURE) { efree(lcname); zend_throw_exception_ex(reflection_exception_ptr, 0 TSRMLS_CC, "Function %s() does not exist", name_str); @@ -1989,7 +1989,7 @@ ZEND_METHOD(reflection_parameter, __construct) lcname_len = Z_STRLEN_P(reference); lcname = zend_str_tolower_dup(Z_STRVAL_P(reference), lcname_len); - if (zend_hash_find(EG(function_table), lcname, lcname_len + 1, (void**) &fptr) == FAILURE) { + if (zend_find_function(EG(function_table), lcname, lcname_len + 1, &fptr TSRMLS_CC) == FAILURE) { efree(lcname); zend_throw_exception_ex(reflection_exception_ptr, 0 TSRMLS_CC, "Function %s() does not exist", Z_STRVAL_P(reference)); @@ -4759,7 +4759,7 @@ ZEND_METHOD(reflection_extension, getFunctions) /* Is there a better way of doing this? */ while (func->fname) { - if (zend_hash_find(EG(function_table), func->fname, strlen(func->fname) + 1, (void**) &fptr) == FAILURE) { + if (zend_find_function(EG(function_table), func->fname, strlen(func->fname) + 1, &fptr TSRMLS_CC) == FAILURE) { zend_error(E_WARNING, "Internal error: Cannot find extension function %s in global function table", func->fname); func++; continue; diff --git a/ext/soap/soap.c b/ext/soap/soap.c index ef16a9b..9ab7d6c 100644 --- a/ext/soap/soap.c +++ b/ext/soap/soap.c @@ -1364,7 +1364,7 @@ PHP_METHOD(SoapServer, setClass) found = zend_lookup_class(classname, classname_len, &ce TSRMLS_CC); #else char *class_name = estrdup(classname); - found = zend_hash_find(EG(class_table), php_strtolower(class_name, classname_len), classname_len + 1, (void **)&ce); + found = zend_find_class(EG(class_table), php_strtolower(class_name, classname_len), classname_len + 1, &ce TSRMLS_CC); efree(class_name); #endif if (found != FAILURE) { @@ -1517,7 +1517,7 @@ PHP_METHOD(SoapServer, addFunction) key = emalloc(key_len + 1); zend_str_tolower_copy(key, Z_STRVAL_PP(tmp_function), key_len); - if (zend_hash_find(EG(function_table), key, key_len+1, (void**)&f) == FAILURE) { + if (zend_find_function(EG(function_table), key, key_len+1, &f TSRMLS_CC) == FAILURE) { php_error_docref(NULL TSRMLS_CC, E_WARNING, "Tried to add a non existant function '%s'", Z_STRVAL_PP(tmp_function)); return; } @@ -1539,7 +1539,7 @@ PHP_METHOD(SoapServer, addFunction) key = emalloc(key_len + 1); zend_str_tolower_copy(key, Z_STRVAL_P(function_name), key_len); - if (zend_hash_find(EG(function_table), key, key_len+1, (void**)&f) == FAILURE) { + if (zend_find_function(EG(function_table), key, key_len+1, &f TSRMLS_CC) == FAILURE) { php_error_docref(NULL TSRMLS_CC, E_WARNING, "Tried to add a non existant function '%s'", Z_STRVAL_P(function_name)); return; } @@ -1592,6 +1592,7 @@ PHP_METHOD(SoapServer, handle) xmlCharEncodingHandlerPtr old_encoding; HashTable *old_class_map, *old_typemap; int old_features; + zend_function *dummy; SOAP_SERVER_BEGIN_CODE(); @@ -1871,6 +1872,7 @@ PHP_METHOD(SoapServer, handle) /* Process soap headers */ if (soap_headers != NULL) { soapHeader *header = soap_headers; + while (header != NULL) { soapHeader *h = header; @@ -1884,9 +1886,11 @@ PHP_METHOD(SoapServer, handle) } fn_name = estrndup(Z_STRVAL(h->function_name),Z_STRLEN(h->function_name)); - if (zend_hash_exists(function_table, php_strtolower(fn_name, Z_STRLEN(h->function_name)), Z_STRLEN(h->function_name) + 1) || - ((service->type == SOAP_CLASS || service->type == SOAP_OBJECT) && - zend_hash_exists(function_table, ZEND_CALL_FUNC_NAME, sizeof(ZEND_CALL_FUNC_NAME)))) { + if ((function_table == EG(function_table) && + zend_find_function(function_table, php_strtolower(fn_name, Z_STRLEN(h->function_name)), Z_STRLEN(h->function_name) + 1, &dummy TSRMLS_CC)) || + zend_hash_exists(function_table, php_strtolower(fn_name, Z_STRLEN(h->function_name)), Z_STRLEN(h->function_name) + 1) || + ((service->type == SOAP_CLASS || service->type == SOAP_OBJECT) && + zend_hash_exists(function_table, ZEND_CALL_FUNC_NAME, sizeof(ZEND_CALL_FUNC_NAME)))) { if (service->type == SOAP_CLASS || service->type == SOAP_OBJECT) { call_status = call_user_function(NULL, &soap_obj, &h->function_name, &h->retval, h->num_params, h->parameters TSRMLS_CC); } else { @@ -1935,9 +1939,11 @@ PHP_METHOD(SoapServer, handle) } fn_name = estrndup(Z_STRVAL(function_name),Z_STRLEN(function_name)); - if (zend_hash_exists(function_table, php_strtolower(fn_name, Z_STRLEN(function_name)), Z_STRLEN(function_name) + 1) || - ((service->type == SOAP_CLASS || service->type == SOAP_OBJECT) && - zend_hash_exists(function_table, ZEND_CALL_FUNC_NAME, sizeof(ZEND_CALL_FUNC_NAME)))) { + if ((function_table == EG(function_table) && + zend_find_function(function_table, php_strtolower(fn_name, Z_STRLEN(function_name)), Z_STRLEN(function_name) + 1, &dummy TSRMLS_CC) == SUCCESS) || + zend_hash_exists(function_table, php_strtolower(fn_name, Z_STRLEN(function_name)), Z_STRLEN(function_name) + 1) || + ((service->type == SOAP_CLASS || service->type == SOAP_OBJECT) && + zend_hash_exists(function_table, ZEND_CALL_FUNC_NAME, sizeof(ZEND_CALL_FUNC_NAME)))) { if (service->type == SOAP_CLASS || service->type == SOAP_OBJECT) { call_status = call_user_function(NULL, &soap_obj, &function_name, retval, num_params, params TSRMLS_CC); if (service->type == SOAP_CLASS) { diff --git a/ext/spl/php_spl.c b/ext/spl/php_spl.c index 264f35f..47090c4 100755 --- a/ext/spl/php_spl.c +++ b/ext/spl/php_spl.c @@ -74,7 +74,7 @@ static zend_class_entry * spl_find_ce_by_name(char *name, int len, zend_bool aut lc_name = do_alloca(len + 1, use_heap); zend_str_tolower_copy(lc_name, name, len); - found = zend_hash_find(EG(class_table), lc_name, len +1, (void **) &ce); + found = zend_find_class(EG(class_table), lc_name, len +1, &ce TSRMLS_CC); free_alloca(lc_name, use_heap); } else { found = zend_lookup_class(name, len, &ce TSRMLS_CC); @@ -228,6 +228,7 @@ static int spl_autoload(const char *class_name, const char * lc_name, int class_ zend_op_array *new_op_array; zval *result = NULL; int ret; + zend_class_entry **dummy_pce; class_file_len = spprintf(&class_file, 0, "%s%s", lc_name, file_extension); @@ -262,7 +263,7 @@ static int spl_autoload(const char *class_name, const char * lc_name, int class_ } efree(class_file); - return zend_hash_exists(EG(class_table), (char*)lc_name, class_name_len+1); + return zend_find_class(EG(class_table), (char*)lc_name, class_name_len+1, &dummy_pce TSRMLS_CC) == SUCCESS; } } efree(class_file); @@ -374,6 +375,7 @@ PHP_FUNCTION(spl_autoload_call) ulong dummy; HashPosition function_pos; autoload_func_info *alfi; + zend_class_entry **dummy_pce; if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z", &class_name) == FAILURE || Z_TYPE_P(class_name) != IS_STRING) { return; @@ -393,7 +395,7 @@ PHP_FUNCTION(spl_autoload_call) if (retval) { zval_ptr_dtor(&retval); } - if (zend_hash_exists(EG(class_table), lc_name, class_name_len + 1)) { + if (zend_find_class(EG(class_table), lc_name, class_name_len + 1, &dummy_pce TSRMLS_CC) == SUCCESS) { break; } zend_hash_move_forward_ex(SPL_G(autoload_functions), &function_pos); @@ -626,7 +628,7 @@ PHP_FUNCTION(spl_autoload_functions) autoload_func_info *alfi; if (!EG(autoload_func)) { - if (zend_hash_find(EG(function_table), ZEND_AUTOLOAD_FUNC_NAME, sizeof(ZEND_AUTOLOAD_FUNC_NAME), (void **) &fptr) == SUCCESS) { + if (zend_find_function(EG(function_table), ZEND_AUTOLOAD_FUNC_NAME, sizeof(ZEND_AUTOLOAD_FUNC_NAME), &fptr TSRMLS_CC) == SUCCESS) { array_init(return_value); add_next_index_stringl(return_value, ZEND_AUTOLOAD_FUNC_NAME, sizeof(ZEND_AUTOLOAD_FUNC_NAME)-1, 1); return; diff --git a/ext/wddx/wddx.c b/ext/wddx/wddx.c index aac89e2..579b8d5 100644 --- a/ext/wddx/wddx.c +++ b/ext/wddx/wddx.c @@ -964,8 +964,8 @@ static void php_wddx_pop_element(void *user_data, const XML_Char *name) zend_bool incomplete_class = 0; zend_str_tolower(Z_STRVAL_P(ent1->data), Z_STRLEN_P(ent1->data)); - if (zend_hash_find(EG(class_table), Z_STRVAL_P(ent1->data), - Z_STRLEN_P(ent1->data)+1, (void **) &pce)==FAILURE) { + if (zend_find_class(EG(class_table), Z_STRVAL_P(ent1->data), + Z_STRLEN_P(ent1->data)+1, &pce TSRMLS_CC)==FAILURE) { incomplete_class = 1; pce = &PHP_IC_ENTRY; }