From cbad7bf66aa4e57514c5f278a7d8cf49236a0752 Mon Sep 17 00:00:00 2001 From: David Carlier Date: Fri, 27 Feb 2026 06:39:25 +0000 Subject: [PATCH 1/2] ext/pcre: simplify pattern info error handling --- ext/pcre/php_pcre.c | 15 ++------------- 1 file changed, 2 insertions(+), 13 deletions(-) diff --git a/ext/pcre/php_pcre.c b/ext/pcre/php_pcre.c index 7b07c8240be04..f8067921700ee 100644 --- a/ext/pcre/php_pcre.c +++ b/ext/pcre/php_pcre.c @@ -826,19 +826,8 @@ PHPAPI pcre_cache_entry* pcre_get_compiled_regex_cache_ex(zend_string *regex, bo new_entry.refcount = 0; new_entry.subpats_table = NULL; - rc = pcre2_pattern_info(re, PCRE2_INFO_CAPTURECOUNT, &new_entry.capture_count); - if (rc < 0) { - if (key != regex) { - zend_string_release_ex(key, 0); - } - pcre2_code_free(new_entry.re); - php_error_docref(NULL, E_WARNING, "Internal pcre2_pattern_info() error %d", rc); - pcre_handle_exec_error(PCRE2_ERROR_INTERNAL); - return NULL; - } - - rc = pcre2_pattern_info(re, PCRE2_INFO_NAMECOUNT, &new_entry.name_count); - if (rc < 0) { + if ((rc = pcre2_pattern_info(re, PCRE2_INFO_CAPTURECOUNT, &new_entry.capture_count)) < 0 || + (rc = pcre2_pattern_info(re, PCRE2_INFO_NAMECOUNT, &new_entry.name_count)) < 0) { if (key != regex) { zend_string_release_ex(key, 0); } From bbaa557d0f6f006947d04fb1ae60df1ad9c0d2b8 Mon Sep 17 00:00:00 2001 From: David Carlier Date: Fri, 27 Feb 2026 21:12:23 +0000 Subject: [PATCH 2/2] ext/pcre: use zend_hash_str_lookup for locale char table management Replace the separate zend_hash_find_ptr + zend_string_init + zend_hash_add_ptr + zend_string_release sequence with a single zend_hash_str_lookup() call which handles find-or-insert in one hash traversal and manages persistent key creation internally. --- ext/pcre/php_pcre.c | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/ext/pcre/php_pcre.c b/ext/pcre/php_pcre.c index f8067921700ee..464c648507843 100644 --- a/ext/pcre/php_pcre.c +++ b/ext/pcre/php_pcre.c @@ -750,21 +750,23 @@ PHPAPI pcre_cache_entry* pcre_get_compiled_regex_cache_ex(zend_string *regex, bo } if (key != regex) { - tables = (uint8_t *)zend_hash_find_ptr(&char_tables, BG(ctype_string)); - if (!tables) { - zend_string *_k; + zv = zend_hash_str_lookup(&char_tables, ZSTR_VAL(BG(ctype_string)), ZSTR_LEN(BG(ctype_string))); + if (Z_ISNULL_P(zv)) { tables = pcre2_maketables(gctx); if (UNEXPECTED(!tables)) { + /* Remove the placeholder entry created by zend_hash_str_lookup(), + * set ptr to NULL first so the destructor (pefree) is safe. */ + ZVAL_PTR(zv, NULL); + zend_hash_str_del(&char_tables, ZSTR_VAL(BG(ctype_string)), ZSTR_LEN(BG(ctype_string))); php_error_docref(NULL,E_WARNING, "Failed to generate locale character tables"); pcre_handle_exec_error(PCRE2_ERROR_NOMEMORY); zend_string_release_ex(key, 0); efree(pattern); return NULL; } - _k = zend_string_init(ZSTR_VAL(BG(ctype_string)), ZSTR_LEN(BG(ctype_string)), 1); - GC_MAKE_PERSISTENT_LOCAL(_k); - zend_hash_add_ptr(&char_tables, _k, (void *)tables); - zend_string_release(_k); + ZVAL_PTR(zv, (void *)tables); + } else { + tables = Z_PTR_P(zv); } } pcre2_set_character_tables(cctx, tables);