From 0d709eceb93df21f954ae88b1adbfd1e312e2bcf Mon Sep 17 00:00:00 2001 From: Gina Peter Banyard Date: Tue, 1 Sep 2026 18:30:21 +0100 Subject: [PATCH 1/7] pcre: reduce scope of variables --- ext/pcre/php_pcre.c | 31 ++++++++++--------------------- 1 file changed, 10 insertions(+), 21 deletions(-) diff --git a/ext/pcre/php_pcre.c b/ext/pcre/php_pcre.c index 4fde4ed5f9b9..cb822bc63274 100644 --- a/ext/pcre/php_pcre.c +++ b/ext/pcre/php_pcre.c @@ -2092,7 +2092,6 @@ static zend_string *php_pcre_replace_array(HashTable *regex, zend_string *tmp_regex_str; zend_string *regex_str = zval_get_tmp_string(regex_entry, &tmp_regex_str); zend_string *replace_entry_str, *tmp_replace_entry_str; - zval *zv; /* Get current entry */ while (1) { @@ -2101,7 +2100,7 @@ static zend_string *php_pcre_replace_array(HashTable *regex, tmp_replace_entry_str = NULL; break; } - zv = ZEND_HASH_ELEMENT(replace_ht, replace_idx); + zval *zv = ZEND_HASH_ELEMENT(replace_ht, replace_idx); replace_idx++; if (Z_TYPE_P(zv) != IS_UNDEF) { replace_entry_str = zval_get_tmp_string(zv, &tmp_replace_entry_str); @@ -2181,14 +2180,13 @@ static zend_string *php_replace_in_subject_func(zend_string *regex_str, const Ha return result; } else { /* If regex is an array */ - zval *regex_entry; ZEND_ASSERT(regex_ht != NULL); zend_string_addref(subject); /* For each entry in the regex array, get the entry */ - ZEND_HASH_FOREACH_VAL(regex_ht, regex_entry) { + ZEND_HASH_FOREACH_VAL(regex_ht, zval *regex_entry) { /* Make sure we're dealing with strings. */ zend_string *tmp_regex_entry_str; zend_string *regex_entry_str = zval_try_get_tmp_string(regex_entry, &tmp_regex_entry_str); @@ -2230,10 +2228,6 @@ static size_t php_preg_replace_func_impl(zval *return_value, } } else { /* if subject is an array */ - zval *subject_entry, zv; - zend_string *string_key; - zend_ulong num_key; - ZEND_ASSERT(subject_ht != NULL); array_init_size(return_value, zend_hash_num_elements(subject_ht)); @@ -2241,7 +2235,7 @@ static size_t php_preg_replace_func_impl(zval *return_value, /* For each subject entry, convert it to string, then perform replacement and add the result to the return_value array. */ - ZEND_HASH_FOREACH_KEY_VAL(subject_ht, num_key, string_key, subject_entry) { + ZEND_HASH_FOREACH_KEY_VAL(subject_ht, zend_ulong num_key, zend_string *string_key, zval *subject_entry) { zend_string *tmp_subject_entry_str; zend_string *subject_entry_str = zval_try_get_tmp_string(subject_entry, &tmp_subject_entry_str); if (UNEXPECTED(subject_entry_str == NULL)) { @@ -2252,6 +2246,7 @@ static size_t php_preg_replace_func_impl(zval *return_value, regex_str, regex_ht, fci, fcc, subject_entry_str, limit_val, &replace_count, flags); if (result != NULL) { /* Add to return array */ + zval zv; ZVAL_STR(&zv, result); if (string_key) { zend_hash_add_new(return_value_ht, string_key, &zv); @@ -2301,10 +2296,6 @@ static void _preg_replace_common( } } else { /* if subject is an array */ - zval *subject_entry, zv; - zend_string *string_key; - zend_ulong num_key; - ZEND_ASSERT(subject_ht != NULL); array_init_size(return_value, zend_hash_num_elements(subject_ht)); @@ -2312,7 +2303,7 @@ static void _preg_replace_common( /* For each subject entry, convert it to string, then perform replacement and add the result to the return_value array. */ - ZEND_HASH_FOREACH_KEY_VAL(subject_ht, num_key, string_key, subject_entry) { + ZEND_HASH_FOREACH_KEY_VAL(subject_ht, zend_ulong num_key, zend_string *string_key, zval *subject_entry) { old_replace_count = replace_count; zend_string *tmp_subject_entry_str; zend_string *subject_entry_str = zval_get_tmp_string(subject_entry, &tmp_subject_entry_str); @@ -2322,6 +2313,7 @@ static void _preg_replace_common( if (result != NULL) { if (!is_filter || replace_count > old_replace_count) { /* Add to return array */ + zval zv; ZVAL_STR(&zv, result); if (string_key) { zend_hash_add_new(return_value_ht, string_key, &zv); @@ -2434,9 +2426,9 @@ PHP_FUNCTION(preg_replace_callback) /* {{{ Perform Perl-style regular expression replacement using replacement callback. */ PHP_FUNCTION(preg_replace_callback_array) { - zval *replace, *zcount = NULL; + zval *zcount = NULL; HashTable *pattern, *subject_ht; - zend_string *subject_str, *str_idx_regex; + zend_string *subject_str; zend_long limit = -1, flags = 0; size_t replace_count = 0; @@ -2456,7 +2448,7 @@ PHP_FUNCTION(preg_replace_callback_array) GC_TRY_ADDREF(subject_str); } - ZEND_HASH_FOREACH_STR_KEY_VAL(pattern, str_idx_regex, replace) { + ZEND_HASH_FOREACH_STR_KEY_VAL(pattern, zend_string *str_idx_regex, zval *replace) { if (!str_idx_regex) { zend_argument_type_error(1, "must contain only string patterns as keys"); goto error; @@ -2924,12 +2916,9 @@ PHP_FUNCTION(preg_grep) PHPAPI void php_pcre_grep_impl(pcre_cache_entry *pce, zval *input, zval *return_value, zend_long flags) /* {{{ */ { - zval *entry; /* An entry in the input array */ uint32_t num_subpats; /* Number of captured subpatterns */ int count; /* Count of matched subpatterns */ uint32_t options; /* Execution options */ - zend_string *string_key; - zend_ulong num_key; bool invert; /* Whether to return non-matching entries */ bool old_mdata_used; @@ -2960,7 +2949,7 @@ PHPAPI void php_pcre_grep_impl(pcre_cache_entry *pce, zval *input, zval *return options = (pce->compile_options & PCRE2_UTF) ? 0 : PCRE2_NO_UTF_CHECK; /* Go through the input array */ - ZEND_HASH_FOREACH_KEY_VAL(Z_ARRVAL_P(input), num_key, string_key, entry) { + ZEND_HASH_FOREACH_KEY_VAL(Z_ARRVAL_P(input), zend_ulong num_key, zend_string *string_key, zval *entry) { zend_string *tmp_subject_str; zend_string *subject_str = zval_get_tmp_string(entry, &tmp_subject_str); From bb204fb237309bca23cebc1bb620b4125564f36f Mon Sep 17 00:00:00 2001 From: Gina Peter Banyard Date: Tue, 1 Sep 2026 18:34:21 +0100 Subject: [PATCH 2/7] pcre: use php_pcre_error_code type instead of int type --- ext/pcre/php_pcre.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ext/pcre/php_pcre.c b/ext/pcre/php_pcre.c index cb822bc63274..30ca49c05d24 100644 --- a/ext/pcre/php_pcre.c +++ b/ext/pcre/php_pcre.c @@ -104,7 +104,7 @@ static void php_pcre_free_char_table(zval *data) static void pcre_handle_exec_error(int pcre_code) /* {{{ */ { - int preg_code = 0; + php_pcre_error_code preg_code = PHP_PCRE_NO_ERROR; switch (pcre_code) { case PCRE2_ERROR_MATCHLIMIT: From 0413e0ed06b1188debce8be36e5fdc3dae5c3e02 Mon Sep 17 00:00:00 2001 From: Gina Peter Banyard Date: Tue, 1 Sep 2026 18:36:27 +0100 Subject: [PATCH 3/7] pcre: use bool type instead of uint8_t --- ext/pcre/php_pcre.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/ext/pcre/php_pcre.c b/ext/pcre/php_pcre.c index 30ca49c05d24..b617c8d2d29a 100644 --- a/ext/pcre/php_pcre.c +++ b/ext/pcre/php_pcre.c @@ -76,7 +76,7 @@ ZEND_TLS pcre2_compile_context *cctx = NULL; ZEND_TLS pcre2_match_context *mctx = NULL; ZEND_TLS pcre2_match_data *mdata = NULL; ZEND_TLS bool mdata_used = 0; -ZEND_TLS uint8_t pcre2_init_ok = 0; +ZEND_TLS bool pcre2_init_ok = false; #if defined(ZTS) && defined(HAVE_PCRE_JIT_SUPPORT) static MUTEX_T pcre_mt = NULL; #define php_pcre_mutex_alloc() \ @@ -204,7 +204,7 @@ static void php_pcre_init_pcre2(uint8_t jit) if (!gctx) { gctx = pcre2_general_context_create(php_pcre_malloc, php_pcre_free, NULL); if (!gctx) { - pcre2_init_ok = 0; + pcre2_init_ok = false; return; } } @@ -212,7 +212,7 @@ static void php_pcre_init_pcre2(uint8_t jit) if (!cctx) { cctx = pcre2_compile_context_create(gctx); if (!cctx) { - pcre2_init_ok = 0; + pcre2_init_ok = false; return; } } @@ -220,7 +220,7 @@ static void php_pcre_init_pcre2(uint8_t jit) if (!mctx) { mctx = pcre2_match_context_create(gctx); if (!mctx) { - pcre2_init_ok = 0; + pcre2_init_ok = false; return; } } @@ -229,7 +229,7 @@ static void php_pcre_init_pcre2(uint8_t jit) if (jit && !jit_stack) { jit_stack = pcre2_jit_stack_create(PCRE_JIT_STACK_MIN_SIZE, PCRE_JIT_STACK_MAX_SIZE, gctx); if (!jit_stack) { - pcre2_init_ok = 0; + pcre2_init_ok = false; return; } } @@ -238,12 +238,12 @@ static void php_pcre_init_pcre2(uint8_t jit) if (!mdata) { mdata = pcre2_match_data_create(PHP_PCRE_PREALLOC_MDATA_SIZE, gctx); if (!mdata) { - pcre2_init_ok = 0; + pcre2_init_ok = false; return; } } - pcre2_init_ok = 1; + pcre2_init_ok = true; }/*}}}*/ static void php_pcre_shutdown_pcre2(void) @@ -277,7 +277,7 @@ static void php_pcre_shutdown_pcre2(void) mdata = NULL; } - pcre2_init_ok = 0; + pcre2_init_ok = false; }/*}}}*/ static PHP_GINIT_FUNCTION(pcre) /* {{{ */ From e653152f6031fc2546cd796ba3368d956a7d04aa Mon Sep 17 00:00:00 2001 From: Gina Peter Banyard Date: Tue, 1 Sep 2026 18:39:48 +0100 Subject: [PATCH 4/7] pcre: add const qualifiers --- ext/pcre/php_pcre.c | 22 +++++++++++----------- ext/pcre/php_pcre.h | 2 +- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/ext/pcre/php_pcre.c b/ext/pcre/php_pcre.c index b617c8d2d29a..2a7f8f7f712c 100644 --- a/ext/pcre/php_pcre.c +++ b/ext/pcre/php_pcre.c @@ -517,7 +517,7 @@ static void free_subpats_table(zend_string **subpat_names, uint32_t num_subpats) } /* {{{ static make_subpats_table */ -static zend_string **make_subpats_table(uint32_t name_cnt, pcre_cache_entry *pce) +static zend_string **make_subpats_table(uint32_t name_cnt, const pcre_cache_entry *pce) { uint32_t num_subpats = pce->capture_count + 1; uint32_t name_size, ni = 0; @@ -553,7 +553,7 @@ static zend_string **ensure_subpats_table(uint32_t name_cnt, pcre_cache_entry *p /* {{{ static calculate_unit_length */ /* Calculates the byte length of the next character. Assumes valid UTF-8 for PCRE2_UTF. */ -static zend_always_inline size_t calculate_unit_length(pcre_cache_entry *pce, const char *start) +static zend_always_inline size_t calculate_unit_length(const pcre_cache_entry *pce, const char *start) { size_t unit_len; @@ -1127,7 +1127,7 @@ static void php_do_pcre_match(INTERNAL_FUNCTION_PARAMETERS, bool global) /* {{{ /* }}} */ static zend_always_inline bool is_known_valid_utf8( - zend_string *subject_str, PCRE2_SIZE start_offset) { + const zend_string *subject_str, PCRE2_SIZE start_offset) { if (!ZSTR_IS_VALID_UTF8(subject_str)) { /* We don't know whether the string is valid UTF-8 or not. */ return false; @@ -2074,8 +2074,8 @@ static zend_always_inline zend_string *php_pcre_replace_func(zend_string *regex, } /* {{{ php_pcre_replace_array */ -static zend_string *php_pcre_replace_array(HashTable *regex, - zend_string *replace_str, HashTable *replace_ht, +static zend_string *php_pcre_replace_array(const HashTable *regex, + zend_string *replace_str, const HashTable *replace_ht, zend_string *subject_str, size_t limit, size_t *replace_count) { zval *regex_entry; @@ -2100,7 +2100,7 @@ static zend_string *php_pcre_replace_array(HashTable *regex, tmp_replace_entry_str = NULL; break; } - zval *zv = ZEND_HASH_ELEMENT(replace_ht, replace_idx); + const zval *zv = ZEND_HASH_ELEMENT(replace_ht, replace_idx); replace_idx++; if (Z_TYPE_P(zv) != IS_UNDEF) { replace_entry_str = zval_get_tmp_string(zv, &tmp_replace_entry_str); @@ -2150,8 +2150,8 @@ static zend_string *php_pcre_replace_array(HashTable *regex, /* {{{ php_replace_in_subject */ static zend_always_inline zend_string *php_replace_in_subject( - zend_string *regex_str, HashTable *regex_ht, - zend_string *replace_str, HashTable *replace_ht, + zend_string *regex_str, const HashTable *regex_ht, + zend_string *replace_str, const HashTable *replace_ht, zend_string *subject, size_t limit, size_t *replace_count) { zend_string *result; @@ -2264,8 +2264,8 @@ static size_t php_preg_replace_func_impl(zval *return_value, static void _preg_replace_common( zval *return_value, HashTable *regex_ht, zend_string *regex_str, - HashTable *replace_ht, zend_string *replace_str, - HashTable *subject_ht, zend_string *subject_str, + const HashTable *replace_ht, zend_string *replace_str, + const HashTable *subject_ht, zend_string *subject_str, zend_long limit, zval *zcount, bool is_filter @@ -2553,7 +2553,7 @@ PHP_FUNCTION(preg_split) /* }}} */ /* {{{ php_pcre_split */ -PHPAPI void php_pcre_split_impl(pcre_cache_entry *pce, zend_string *subject_str, zval *return_value, +PHPAPI void php_pcre_split_impl(const pcre_cache_entry *pce, zend_string *subject_str, zval *return_value, zend_long limit_val, zend_long flags) { uint32_t options; /* Execution options */ diff --git a/ext/pcre/php_pcre.h b/ext/pcre/php_pcre.h index ebaa686a31c3..5ab142582d53 100644 --- a/ext/pcre/php_pcre.h +++ b/ext/pcre/php_pcre.h @@ -53,7 +53,7 @@ PHPAPI void php_pcre_match_impl(pcre_cache_entry *pce, zend_string *subject_str PHPAPI zend_string *php_pcre_replace_impl(pcre_cache_entry *pce, zend_string *subject_str, const char *subject, size_t subject_len, zend_string *replace_str, size_t limit, size_t *replace_count); -PHPAPI void php_pcre_split_impl( pcre_cache_entry *pce, zend_string *subject_str, zval *return_value, +PHPAPI void php_pcre_split_impl(const pcre_cache_entry *pce, zend_string *subject_str, zval *return_value, zend_long limit_val, zend_long flags); PHPAPI void php_pcre_grep_impl( pcre_cache_entry *pce, zval *input, zval *return_value, From 946864e9787535b8d9393ff2e039acb638b4b062 Mon Sep 17 00:00:00 2001 From: Gina Peter Banyard Date: Tue, 1 Sep 2026 18:44:41 +0100 Subject: [PATCH 5/7] pcre: use zend_hash APIs that use zend_strings Instead of a const char*, size_t pair --- ext/pcre/php_pcre.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/ext/pcre/php_pcre.c b/ext/pcre/php_pcre.c index 2a7f8f7f712c..91974239c100 100644 --- a/ext/pcre/php_pcre.c +++ b/ext/pcre/php_pcre.c @@ -750,14 +750,14 @@ PHPAPI pcre_cache_entry* pcre_get_compiled_regex_cache_ex(zend_string *regex, bo } if (key != regex) { - zv = zend_hash_str_lookup(&char_tables, ZSTR_VAL(BG(ctype_string)), ZSTR_LEN(BG(ctype_string))); + zv = zend_hash_lookup(&char_tables, 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(), + /* Remove the placeholder entry created by zend_hash_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))); + zend_hash_del(&char_tables, 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); From 59ee55bd4800e99546009c2adc43fedd9709ac13 Mon Sep 17 00:00:00 2001 From: Gina Peter Banyard Date: Tue, 1 Sep 2026 20:06:19 +0100 Subject: [PATCH 6/7] pcre: refactor preg_get_backref() --- ext/pcre/php_pcre.c | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/ext/pcre/php_pcre.c b/ext/pcre/php_pcre.c index 91974239c100..a2ab9f66e715 100644 --- a/ext/pcre/php_pcre.c +++ b/ext/pcre/php_pcre.c @@ -1515,17 +1515,17 @@ PHP_FUNCTION(preg_match_all) } /* }}} */ -/* {{{ preg_get_backref */ -static int preg_get_backref(char **str, int *backref) +static bool preg_get_backref(char **str, int *backref) { - char in_brace = 0; + bool in_brace = false; char *walk = *str; - if (walk[1] == 0) - return 0; + if (walk[1] == 0) { + return false; + } if (*walk == '$' && walk[1] == '{') { - in_brace = 1; + in_brace = true; walk++; } walk++; @@ -1533,8 +1533,9 @@ static int preg_get_backref(char **str, int *backref) if (*walk >= '0' && *walk <= '9') { *backref = *walk - '0'; walk++; - } else - return 0; + } else { + return false; + } if (*walk && *walk >= '0' && *walk <= '9') { *backref = *backref * 10 + *walk - '0'; @@ -1542,16 +1543,15 @@ static int preg_get_backref(char **str, int *backref) } if (in_brace) { - if (*walk != '}') - return 0; - else - walk++; + if (*walk != '}') { + return false; + } + walk++; } *str = walk; - return 1; + return true; } -/* }}} */ /* Return NULL if an exception has occurred */ static zend_string *preg_do_repl_func(zend_fcall_info *fci, zend_fcall_info_cache *fcc, const char *subject, PCRE2_SIZE *offsets, zend_string **subpat_names, uint32_t num_subpats, int count, const PCRE2_SPTR mark, zend_long flags) From 4554b1a5a31edbbf029983682af7709382b880d3 Mon Sep 17 00:00:00 2001 From: Gina Peter Banyard Date: Tue, 1 Sep 2026 20:14:49 +0100 Subject: [PATCH 7/7] pcre: pass subject as zend_string* to preg_do_repl_func() --- ext/pcre/php_pcre.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/ext/pcre/php_pcre.c b/ext/pcre/php_pcre.c index a2ab9f66e715..78eb280ed0fc 100644 --- a/ext/pcre/php_pcre.c +++ b/ext/pcre/php_pcre.c @@ -1554,14 +1554,14 @@ static bool preg_get_backref(char **str, int *backref) } /* Return NULL if an exception has occurred */ -static zend_string *preg_do_repl_func(zend_fcall_info *fci, zend_fcall_info_cache *fcc, const char *subject, PCRE2_SIZE *offsets, zend_string **subpat_names, uint32_t num_subpats, int count, const PCRE2_SPTR mark, zend_long flags) +static zend_string *preg_do_repl_func(zend_fcall_info *fci, zend_fcall_info_cache *fcc, const zend_string *subject, PCRE2_SIZE *offsets, zend_string **subpat_names, uint32_t num_subpats, int count, const PCRE2_SPTR mark, zend_long flags) { zend_string *result_str = NULL; zval retval; /* Function return value */ zval arg; /* Argument to pass to function */ array_init_size(&arg, count + (mark ? 1 : 0)); - populate_subpat_array(Z_ARRVAL(arg), subject, offsets, subpat_names, num_subpats, count, mark, flags); + populate_subpat_array(Z_ARRVAL(arg), ZSTR_VAL(subject), offsets, subpat_names, num_subpats, count, mark, flags); fci->retval = &retval; fci->param_count = 1; @@ -1953,7 +1953,7 @@ static zend_string *php_pcre_replace_func_impl(pcre_cache_entry *pce, zend_strin /* Use custom function to get replacement string and its length. */ zend_string *eval_result = preg_do_repl_func( - fci, fcc, ZSTR_VAL(subject_str), offsets, subpat_names, num_subpats, count, + fci, fcc, subject_str, offsets, subpat_names, num_subpats, count, pcre2_get_mark(match_data), flags); if (UNEXPECTED(eval_result == NULL)) {