Commit 21bf7f67ff0 for php.net
commit 21bf7f67ff0e53eee15d79d5a8862e2f1c4a37c4
Author: Jorg Adam Sowa <jorg.sowa@gmail.com>
Date: Sat Jul 4 20:07:49 2026 +0200
phpdbg: Fix off-by-one in phpdbg_safe_class_lookup() signal-safe class lookup (#22593)
lc_length was set to name_length + 1, one past the actual lowercased
string length, so zend_hash_str_find_ptr() (which expects a strlen-style
length) never matched an existing class entry. This made class lookups
during phpdbg's signal-handler interruption path always fail silently.
Replaced the manual emalloc/tolower/efree dance with
zend_hash_str_find_ptr_lc(), which performs the lowercase copy and
lookup in one call and removes the surface for this class of bug.
diff --git a/NEWS b/NEWS
index 08a852a5a0d..d950ce969fc 100644
--- a/NEWS
+++ b/NEWS
@@ -44,6 +44,8 @@ PHP NEWS
. Fixed bug GH-17387 (Trivial crash in phpdbg lexer). (iliaal)
. Fixed fleaked lowercased lookup keys in phpdbg_resolve_opline_break.
(jorgsowa)
+ . Fixed off-by-one in phpdbg_safe_class_lookup() causing class lookups to
+ always fail during phpdbg's signal-safe interruption path. (jorgsowa)
- Reflection:
. Fixed bug GH-22324 (Ignore leading namespace separator in
diff --git a/sapi/phpdbg/phpdbg_utils.c b/sapi/phpdbg/phpdbg_utils.c
index 7465004e99a..b3d3445b627 100644
--- a/sapi/phpdbg/phpdbg_utils.c
+++ b/sapi/phpdbg/phpdbg_utils.c
@@ -397,29 +397,20 @@ PHPDBG_API void phpdbg_set_async_io(int fd) {
int phpdbg_safe_class_lookup(const char *name, int name_length, zend_class_entry **ce) {
if (PHPDBG_G(flags) & PHPDBG_IN_SIGNAL_HANDLER) {
- char *lc_name, *lc_free;
- int lc_length;
-
if (name == NULL || !name_length) {
return FAILURE;
}
- lc_free = lc_name = emalloc(name_length + 1);
- zend_str_tolower_copy(lc_name, name, name_length);
- lc_length = name_length + 1;
-
- if (lc_name[0] == '\\') {
- lc_name += 1;
- lc_length -= 1;
+ if (name[0] == '\\') {
+ name += 1;
+ name_length -= 1;
}
phpdbg_try_access {
- *ce = zend_hash_str_find_ptr(EG(class_table), lc_name, lc_length);
+ *ce = zend_hash_str_find_ptr_lc(EG(class_table), name, name_length);
} phpdbg_catch_access {
phpdbg_error("Could not fetch class %.*s, invalid data source", name_length, name);
} phpdbg_end_try_access();
-
- efree(lc_free);
} else {
zend_string *str_name = zend_string_init(name, name_length, 0);
*ce = zend_lookup_class(str_name);