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);