Commit 39b66bae333 for php.net
commit 39b66bae333eabb173476d09de1106890bc94980
Author: Jorg Adam Sowa <jorg.sowa@gmail.com>
Date: Fri Jul 3 01:53:33 2026 +0200
Use zend_hash_find_ptr_lc() for case-insensitive name lookups (#22565)
A number of call sites lowercased a class/function/method name into a
temporary string solely to use it as a lookup key in the class table,
function table, module registry, etc., then released it. Replace those
with zend_hash_find_ptr_lc() / zend_hash_str_find_ptr_lc(), which
lowercase into a stack buffer (for short names), perform the lookup, and
free the temporary internally.
This removes the manual tolower + release boilerplate at 17 sites and
avoids a heap allocation for the common short-name case. No behavior
change.
diff --git a/Zend/Optimizer/zend_optimizer.c b/Zend/Optimizer/zend_optimizer.c
index d10b4d83fc3..0173d2ef47a 100644
--- a/Zend/Optimizer/zend_optimizer.c
+++ b/Zend/Optimizer/zend_optimizer.c
@@ -104,9 +104,7 @@ zend_result zend_optimizer_eval_special_func_call(
zval *result, const zend_string *name, zend_string *arg) {
if (zend_string_equals_literal(name, "function_exists") ||
zend_string_equals_literal(name, "is_callable")) {
- zend_string *lc_name = zend_string_tolower(arg);
- const zend_internal_function *func = zend_hash_find_ptr(EG(function_table), lc_name);
- zend_string_release_ex(lc_name, 0);
+ const zend_internal_function *func = zend_hash_find_ptr_lc(EG(function_table), arg);
if (func && func->type == ZEND_INTERNAL_FUNCTION
&& func->module->type == MODULE_PERSISTENT
@@ -120,9 +118,7 @@ zend_result zend_optimizer_eval_special_func_call(
return FAILURE;
}
if (zend_string_equals_literal(name, "extension_loaded")) {
- zend_string *lc_name = zend_string_tolower(arg);
- zend_module_entry *m = zend_hash_find_ptr(&module_registry, lc_name);
- zend_string_release_ex(lc_name, 0);
+ zend_module_entry *m = zend_hash_find_ptr_lc(&module_registry, arg);
if (!m) {
if (PG(enable_dl)) {
diff --git a/Zend/zend_builtin_functions.c b/Zend/zend_builtin_functions.c
index 2dceac2512d..87acf073a2d 100644
--- a/Zend/zend_builtin_functions.c
+++ b/Zend/zend_builtin_functions.c
@@ -953,7 +953,6 @@ ZEND_FUNCTION(method_exists)
{
zval *klass;
zend_string *method_name;
- zend_string *lcname;
zend_class_entry *ce;
zend_function *func;
@@ -974,9 +973,7 @@ ZEND_FUNCTION(method_exists)
RETURN_THROWS();
}
- lcname = zend_string_tolower(method_name);
- func = zend_hash_find_ptr(&ce->function_table, lcname);
- zend_string_release_ex(lcname, 0);
+ func = zend_hash_find_ptr_lc(&ce->function_table, method_name);
if (func) {
/* Exclude shadow properties when checking a method on a specific class. Include
@@ -2219,7 +2216,6 @@ ZEND_FUNCTION(extension_loaded)
ZEND_FUNCTION(get_extension_funcs)
{
zend_string *extension_name;
- zend_string *lcname;
bool array;
zend_module_entry *module;
zend_function *zif;
@@ -2228,9 +2224,7 @@ ZEND_FUNCTION(get_extension_funcs)
RETURN_THROWS();
}
if (strncasecmp(ZSTR_VAL(extension_name), "zend", sizeof("zend"))) {
- lcname = zend_string_tolower(extension_name);
- module = zend_hash_find_ptr(&module_registry, lcname);
- zend_string_release_ex(lcname, 0);
+ module = zend_hash_find_ptr_lc(&module_registry, extension_name);
} else {
module = zend_hash_str_find_ptr(&module_registry, "core", sizeof("core") - 1);
}
diff --git a/Zend/zend_inheritance.c b/Zend/zend_inheritance.c
index 8df6a5599d3..848b9d209b2 100644
--- a/Zend/zend_inheritance.c
+++ b/Zend/zend_inheritance.c
@@ -264,11 +264,7 @@ static zend_class_entry *lookup_class_ex(
bool in_preload = CG(compiler_options) & ZEND_COMPILE_PRELOAD;
if (UNEXPECTED(!EG(active) && !in_preload)) {
- zend_string *lc_name = zend_string_tolower(name);
-
- ce = zend_hash_find_ptr(CG(class_table), lc_name);
-
- zend_string_release(lc_name);
+ ce = zend_hash_find_ptr_lc(CG(class_table), name);
if (register_unresolved && !ce) {
zend_error_noreturn(
@@ -2530,7 +2526,6 @@ static void zend_traits_init_trait_structures(zend_class_entry *ce, zend_class_e
size_t i, j = 0;
zend_trait_precedence *cur_precedence;
zend_trait_method_reference *cur_method_ref;
- zend_string *lc_trait_name;
zend_string *lcname;
HashTable **exclude_tables = NULL;
zend_class_entry **aliases = NULL;
@@ -2545,9 +2540,7 @@ static void zend_traits_init_trait_structures(zend_class_entry *ce, zend_class_e
while ((cur_precedence = precedences[i])) {
/** Resolve classes for all precedence operations. */
cur_method_ref = &cur_precedence->trait_method;
- lc_trait_name = zend_string_tolower(cur_method_ref->class_name);
- trait = zend_hash_find_ptr(EG(class_table), lc_trait_name);
- zend_string_release_ex(lc_trait_name, 0);
+ trait = zend_hash_find_ptr_lc(EG(class_table), cur_method_ref->class_name);
if (!trait || !(trait->ce_flags & ZEND_ACC_LINKED)) {
zend_error_noreturn(E_COMPILE_ERROR, "Could not find trait %s", ZSTR_VAL(cur_method_ref->class_name));
}
@@ -2574,9 +2567,7 @@ static void zend_traits_init_trait_structures(zend_class_entry *ce, zend_class_e
zend_class_entry *exclude_ce;
uint32_t trait_num;
- lc_trait_name = zend_string_tolower(class_name);
- exclude_ce = zend_hash_find_ptr(EG(class_table), lc_trait_name);
- zend_string_release_ex(lc_trait_name, 0);
+ exclude_ce = zend_hash_find_ptr_lc(EG(class_table), class_name);
if (!exclude_ce || !(exclude_ce->ce_flags & ZEND_ACC_LINKED)) {
zend_error_noreturn(E_COMPILE_ERROR, "Could not find trait %s", ZSTR_VAL(class_name));
}
@@ -2619,9 +2610,7 @@ static void zend_traits_init_trait_structures(zend_class_entry *ce, zend_class_e
lcname = zend_string_tolower(cur_method_ref->method_name);
if (cur_method_ref->class_name) {
/* For all aliases with an explicit class name, resolve the class now. */
- lc_trait_name = zend_string_tolower(cur_method_ref->class_name);
- trait = zend_hash_find_ptr(EG(class_table), lc_trait_name);
- zend_string_release_ex(lc_trait_name, 0);
+ trait = zend_hash_find_ptr_lc(EG(class_table), cur_method_ref->class_name);
if (!trait || !(trait->ce_flags & ZEND_ACC_LINKED)) {
zend_error_noreturn(E_COMPILE_ERROR, "Could not find trait %s", ZSTR_VAL(cur_method_ref->class_name));
}
diff --git a/ext/hash/hash.c b/ext/hash/hash.c
index e2af98c81dd..74abf02acd8 100644
--- a/ext/hash/hash.c
+++ b/ext/hash/hash.c
@@ -102,9 +102,7 @@ static struct mhash_bc_entry mhash_to_hash[MHASH_NUM_ALGOS] = {
PHP_HASH_API const php_hash_ops *php_hash_fetch_ops(zend_string *algo) /* {{{ */
{
- zend_string *lower = zend_string_tolower(algo);
- const php_hash_ops *ops = zend_hash_find_ptr(&php_hash_hashtable, lower);
- zend_string_release(lower);
+ const php_hash_ops *ops = zend_hash_find_ptr_lc(&php_hash_hashtable, algo);
return ops;
}
diff --git a/ext/opcache/ZendAccelerator.c b/ext/opcache/ZendAccelerator.c
index 83e933b0118..6f606d9d37d 100644
--- a/ext/opcache/ZendAccelerator.c
+++ b/ext/opcache/ZendAccelerator.c
@@ -3847,9 +3847,7 @@ static zend_result preload_resolve_deps(preload_error *error, const zend_class_e
memset(error, 0, sizeof(preload_error));
if (ce->parent_name) {
- zend_string *key = zend_string_tolower(ce->parent_name);
- const zend_class_entry *parent = zend_hash_find_ptr(EG(class_table), key);
- zend_string_release(key);
+ const zend_class_entry *parent = zend_hash_find_ptr_lc(EG(class_table), ce->parent_name);
if (!parent) {
error->kind = "Unknown parent ";
error->name = ZSTR_VAL(ce->parent_name);
diff --git a/ext/pdo/pdo_dbh.c b/ext/pdo/pdo_dbh.c
index 6a47ec30c86..dcd9f7b126d 100644
--- a/ext/pdo/pdo_dbh.c
+++ b/ext/pdo/pdo_dbh.c
@@ -1484,7 +1484,6 @@ static zend_function *dbh_method_get(zend_object **object, zend_string *method_n
{
zend_function *fbc = NULL;
pdo_dbh_object_t *dbh_obj = php_pdo_dbh_fetch_object(*object);
- zend_string *lc_method_name;
if ((fbc = zend_std_get_method(object, method_name, key)) == NULL) {
/* not a pre-defined method, nor a user-defined method; check
@@ -1497,9 +1496,7 @@ static zend_function *dbh_method_get(zend_object **object, zend_string *method_n
}
}
- lc_method_name = zend_string_tolower(method_name);
- fbc = zend_hash_find_ptr(dbh_obj->inner->cls_methods[PDO_DBH_DRIVER_METHOD_KIND_DBH], lc_method_name);
- zend_string_release_ex(lc_method_name, 0);
+ fbc = zend_hash_find_ptr_lc(dbh_obj->inner->cls_methods[PDO_DBH_DRIVER_METHOD_KIND_DBH], method_name);
}
out:
diff --git a/ext/reflection/php_reflection.c b/ext/reflection/php_reflection.c
index a9f6b579977..37c45cb0216 100644
--- a/ext/reflection/php_reflection.c
+++ b/ext/reflection/php_reflection.c
@@ -859,7 +859,6 @@ static void _function_string(smart_str *str, const zend_function *fptr, const ze
{
smart_str param_indent = {0};
zend_function *overwrites;
- zend_string *lc_name;
/* TBD: Repair indenting of doc comment (or is this to be done in the parser?)
* What's "wrong" is that any whitespace before the doc comment start is
@@ -885,13 +884,11 @@ static void _function_string(smart_str *str, const zend_function *fptr, const ze
if (fptr->common.scope != scope) {
smart_str_append_printf(str, ", inherits %s", ZSTR_VAL(fptr->common.scope->name));
} else if (fptr->common.scope->parent) {
- lc_name = zend_string_tolower(fptr->common.function_name);
- if ((overwrites = zend_hash_find_ptr(&fptr->common.scope->parent->function_table, lc_name)) != NULL) {
+ if ((overwrites = zend_hash_find_ptr_lc(&fptr->common.scope->parent->function_table, fptr->common.function_name)) != NULL) {
if (fptr->common.scope != overwrites->common.scope && !(overwrites->common.fn_flags & ZEND_ACC_PRIVATE)) {
smart_str_append_printf(str, ", overwrites %s", ZSTR_VAL(overwrites->common.scope->name));
}
}
- zend_string_release_ex(lc_name, 0);
}
}
if (fptr->common.prototype && fptr->common.prototype->common.scope) {
diff --git a/sapi/cli/php_cli.c b/sapi/cli/php_cli.c
index 9a05f8e6854..e5e573d1533 100644
--- a/sapi/cli/php_cli.c
+++ b/sapi/cli/php_cli.c
@@ -1093,10 +1093,9 @@ static int do_cli(int argc, char **argv) /* {{{ */
case PHP_CLI_MODE_REFLECTION_EXT_INFO:
{
size_t len = strlen(reflection_what);
- char *lcname = zend_str_tolower_dup(reflection_what, len);
zend_module_entry *module;
- if ((module = zend_hash_str_find_ptr(&module_registry, lcname, len)) == NULL) {
+ if ((module = zend_hash_str_find_ptr_lc(&module_registry, reflection_what, len)) == NULL) {
if (!strcmp(reflection_what, "main")) {
display_ini_entries(NULL);
} else {
@@ -1107,7 +1106,6 @@ static int do_cli(int argc, char **argv) /* {{{ */
php_info_print_module(module);
}
- efree(lcname);
break;
}
diff --git a/sapi/phpdbg/phpdbg_bp.c b/sapi/phpdbg/phpdbg_bp.c
index 4dfa89d4b0f..b9c3436280c 100644
--- a/sapi/phpdbg/phpdbg_bp.c
+++ b/sapi/phpdbg/phpdbg_bp.c
@@ -966,13 +966,7 @@ static inline phpdbg_breakbase_t *phpdbg_find_breakpoint_symbol(zend_function *f
}
if (ops->function_name) {
- phpdbg_breakbase_t *brake;
- zend_string *fname = zend_string_tolower(ops->function_name);
-
- brake = zend_hash_find_ptr(&PHPDBG_G(bp)[PHPDBG_BREAK_SYM], fname);
-
- zend_string_release(fname);
- return brake;
+ return zend_hash_find_ptr_lc(&PHPDBG_G(bp)[PHPDBG_BREAK_SYM], ops->function_name);
} else {
return zend_hash_str_find_ptr(&PHPDBG_G(bp)[PHPDBG_BREAK_SYM], ZEND_STRL("main"));
}
@@ -982,17 +976,11 @@ static inline phpdbg_breakbase_t *phpdbg_find_breakpoint_method(zend_op_array *o
{
HashTable *class_table;
phpdbg_breakbase_t *brake = NULL;
- zend_string *class_lcname = zend_string_tolower(ops->scope->name);
-
- if ((class_table = zend_hash_find_ptr(&PHPDBG_G(bp)[PHPDBG_BREAK_METHOD], class_lcname))) {
- zend_string *lcname = zend_string_tolower(ops->function_name);
-
- brake = zend_hash_find_ptr(class_table, lcname);
- zend_string_release(lcname);
+ if ((class_table = zend_hash_find_ptr_lc(&PHPDBG_G(bp)[PHPDBG_BREAK_METHOD], ops->scope->name))) {
+ brake = zend_hash_find_ptr_lc(class_table, ops->function_name);
}
- zend_string_release(class_lcname);
return brake;
} /* }}} */
diff --git a/sapi/phpdbg/phpdbg_list.c b/sapi/phpdbg/phpdbg_list.c
index 505b04e81f9..3931fc9c152 100644
--- a/sapi/phpdbg/phpdbg_list.c
+++ b/sapi/phpdbg/phpdbg_list.c
@@ -88,15 +88,12 @@ PHPDBG_LIST(method) /* {{{ */
if (phpdbg_safe_class_lookup(param->method.class, strlen(param->method.class), &ce) == SUCCESS) {
zend_function *function;
- char *lcname = zend_str_tolower_dup(param->method.name, strlen(param->method.name));
- if ((function = zend_hash_str_find_ptr(&ce->function_table, lcname, strlen(lcname)))) {
+ if ((function = zend_hash_str_find_ptr_lc(&ce->function_table, param->method.name, strlen(param->method.name)))) {
phpdbg_list_function(function);
} else {
phpdbg_error("Could not find %s::%s", param->method.class, param->method.name);
}
-
- efree(lcname);
} else {
phpdbg_error("Could not find the class %s", param->method.class);
}