From 6d46d0b42b32c3f5404975f04f8f03ba9231b770 Mon Sep 17 00:00:00 2001 From: Gina Peter Banyard Date: Sat, 26 Sep 2026 16:32:09 +0100 Subject: [PATCH 1/7] pcre: minor clean-up of PHP_MINFO_FUNCTION(pcre) --- ext/pcre/php_pcre.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/ext/pcre/php_pcre.c b/ext/pcre/php_pcre.c index 4c63ab0920ae..3b63d5916918 100644 --- a/ext/pcre/php_pcre.c +++ b/ext/pcre/php_pcre.c @@ -369,10 +369,6 @@ static char *_pcre2_config_str(uint32_t what) /* {{{ PHP_MINFO_FUNCTION(pcre) */ static PHP_MINFO_FUNCTION(pcre) { -#ifdef HAVE_PCRE_JIT_SUPPORT - uint32_t flag = 0; - char *jit_target = _pcre2_config_str(PCRE2_CONFIG_JITTARGET); -#endif char *version = _pcre2_config_str(PCRE2_CONFIG_VERSION); char *unicode = _pcre2_config_str(PCRE2_CONFIG_UNICODE_VERSION); @@ -384,6 +380,8 @@ static PHP_MINFO_FUNCTION(pcre) free(unicode); #ifdef HAVE_PCRE_JIT_SUPPORT + uint32_t flag = 0; + char *jit_target = _pcre2_config_str(PCRE2_CONFIG_JITTARGET); if (!pcre2_config(PCRE2_CONFIG_JIT, &flag)) { php_info_print_table_row(2, "PCRE JIT Support", flag ? "enabled" : "disabled"); } else { From 7d33c580dba8145e332b668062a1e588d8cad3cc Mon Sep 17 00:00:00 2001 From: Gina Peter Banyard Date: Sat, 26 Sep 2026 17:48:07 +0100 Subject: [PATCH 2/7] pcre: add comment for when constant was defined --- 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 3b63d5916918..7a11a6216391 100644 --- a/ext/pcre/php_pcre.c +++ b/ext/pcre/php_pcre.c @@ -708,7 +708,7 @@ PHPAPI pcre_cache_entry* pcre_get_compiled_regex_cache_ex(zend_string *regex, bo /* PCRE specific options */ case 'A': coptions |= PCRE2_ANCHORED; break; case 'D': coptions |= PCRE2_DOLLAR_ENDONLY;break; -#ifdef PCRE2_EXTRA_CASELESS_RESTRICT +#ifdef PCRE2_EXTRA_CASELESS_RESTRICT /* Added in 10.43 (16-February-2024) */ case 'r': eoptions |= PCRE2_EXTRA_CASELESS_RESTRICT; break; #endif case 'S': /* Pass. */ break; From 91ce53d6b1b12e81fe090ecbc81e7ca9bf894820 Mon Sep 17 00:00:00 2001 From: Gina Peter Banyard Date: Sat, 26 Sep 2026 13:25:45 +0100 Subject: [PATCH 3/7] pcre: drop some ZPP tests --- ext/pcre/tests/preg_grep_error1.phpt | 17 ----------------- ext/pcre/tests/preg_match_all_error1.phpt | 23 ++--------------------- ext/pcre/tests/preg_replace_error1.phpt | 7 ------- ext/pcre/tests/preg_replace_error2.phpt | 12 ++++-------- ext/pcre/tests/preg_split_error1.phpt | 19 +------------------ 5 files changed, 7 insertions(+), 71 deletions(-) diff --git a/ext/pcre/tests/preg_grep_error1.phpt b/ext/pcre/tests/preg_grep_error1.phpt index 0c1a4733ca90..2629f5aa52d3 100644 --- a/ext/pcre/tests/preg_grep_error1.phpt +++ b/ext/pcre/tests/preg_grep_error1.phpt @@ -13,26 +13,11 @@ $values = [ '/[a-zA-Z]', //Regex without closing delimiter '[a-zA-Z]/', //Regex without opening delimiter '/[a-zA-Z]/F', - [ - '[a-z]', //Array of Regexes - '[A-Z]', - '[0-9]', - ], '/[a-zA-Z]/', //Regex string ]; $array = [123, 'abc', 'test']; foreach ($values as $value) { - try { - var_dump(preg_grep($value, $array)); - } catch (TypeError $e) { - echo $e::class, ': ', $e->getMessage(), "\n"; - } -} -$value = new stdclass(); //Object -try { var_dump(preg_grep($value, $array)); -} catch (TypeError $e) { - echo $e::class, ': ', $e->getMessage(), "\n"; } ?> --EXPECTF-- @@ -47,11 +32,9 @@ bool(false) Warning: preg_grep(): Unknown modifier 'F' in %spreg_grep_error1.php on line %d bool(false) -TypeError: preg_grep(): Argument #1 ($pattern) must be of type string, array given array(2) { [1]=> string(3) "abc" [2]=> string(4) "test" } -TypeError: preg_grep(): Argument #1 ($pattern) must be of type string, stdClass given diff --git a/ext/pcre/tests/preg_match_all_error1.phpt b/ext/pcre/tests/preg_match_all_error1.phpt index 4965cc1913bb..d2d212fc6c46 100644 --- a/ext/pcre/tests/preg_match_all_error1.phpt +++ b/ext/pcre/tests/preg_match_all_error1.phpt @@ -13,29 +13,14 @@ $regex_array = [ '/[a-zA-Z]', //Regex without closing delimiter '[a-zA-Z]/', //Regex without opening delimiter '/[a-zA-Z]/F', - [ - '[a-z]', //Array of Regexes - '[A-Z]', - '[0-9]', - ], '/[a-zA-Z]/', //Regex string ]; $subject = 'test'; foreach ($regex_array as $regex_value) { - try { - var_dump(preg_match_all($regex_value, $subject, $matches1)); - } catch (TypeError $e) { - echo $e::class, ': ', $e->getMessage(), "\n"; - } + var_dump(preg_match_all($regex_value, $subject, $matches1)); var_dump($matches1); } -$regex_value = new stdclass(); //Object -try { - var_dump(preg_match_all($regex_value, $subject, $matches)); -} catch (TypeError $e) { - echo $e::class, ': ', $e->getMessage(), "\n"; -} -var_dump($matches); + ?> --EXPECTF-- Warning: preg_match_all(): Delimiter must not be alphanumeric, backslash, or NUL byte in %spreg_match_all_error1.php on line %d @@ -53,8 +38,6 @@ NULL Warning: preg_match_all(): Unknown modifier 'F' in %spreg_match_all_error1.php on line %d bool(false) NULL -TypeError: preg_match_all(): Argument #1 ($pattern) must be of type string, array given -NULL int(4) array(1) { [0]=> @@ -69,5 +52,3 @@ array(1) { string(1) "t" } } -TypeError: preg_match_all(): Argument #1 ($pattern) must be of type string, stdClass given -NULL diff --git a/ext/pcre/tests/preg_replace_error1.phpt b/ext/pcre/tests/preg_replace_error1.phpt index 5219496a5535..ff19998d8c5a 100644 --- a/ext/pcre/tests/preg_replace_error1.phpt +++ b/ext/pcre/tests/preg_replace_error1.phpt @@ -25,12 +25,6 @@ $subject = 'a'; foreach ($regex_array as $regex_value) { var_dump(preg_replace($regex_value, $replace, $subject)); } -$regex_value = new stdclass(); //Object -try { - var_dump(preg_replace($regex_value, $replace, $subject)); -} catch (Error $e) { - echo $e::class, ': ', $e->getMessage(), "\n"; -} ?> --EXPECTF-- Warning: preg_replace(): Delimiter must not be alphanumeric, backslash, or NUL byte in %spreg_replace_error1.php on line %d @@ -46,4 +40,3 @@ Warning: preg_replace(): Unknown modifier 'F' in %spreg_replace_error1.php on li NULL string(1) "a" string(1) "1" -TypeError: preg_replace(): Argument #1 ($pattern) must be of type array|string, stdClass given diff --git a/ext/pcre/tests/preg_replace_error2.phpt b/ext/pcre/tests/preg_replace_error2.phpt index 6b4a1bfae934..d007a6c9946d 100644 --- a/ext/pcre/tests/preg_replace_error2.phpt +++ b/ext/pcre/tests/preg_replace_error2.phpt @@ -9,7 +9,10 @@ Test preg_replace() function : error conditions - wrong arg types * Testing how preg_replace reacts to being passed the wrong type of replacement argument */ $regex = '/[a-zA-Z]/'; -$replace = array('this is a string', array('this is', 'a subarray'),); +$replace = [ + 'this is a string', + ['this is', 'a subarray'], +]; $subject = 'test'; foreach($replace as $value) { try { @@ -18,14 +21,7 @@ foreach($replace as $value) { echo $e::class, ': ', $e->getMessage(), "\n"; } } -$value = new stdclass(); //Object -try { - var_dump(preg_replace($regex, $value, $subject)); -} catch (Error $e) { - echo $e::class, ': ', $e->getMessage(), "\n"; -} ?> --EXPECT-- string(64) "this is a stringthis is a stringthis is a stringthis is a string" TypeError: preg_replace(): Argument #1 ($pattern) must be of type array when argument #2 ($replacement) is an array, string given -TypeError: preg_replace(): Argument #2 ($replacement) must be of type array|string, stdClass given diff --git a/ext/pcre/tests/preg_split_error1.phpt b/ext/pcre/tests/preg_split_error1.phpt index 9e9fd8c7133d..309c494143c2 100644 --- a/ext/pcre/tests/preg_split_error1.phpt +++ b/ext/pcre/tests/preg_split_error1.phpt @@ -13,26 +13,11 @@ $regex_array = [ '/[a-zA-Z]', //Regex without closing delimiter '[a-zA-Z]/', //Regex without opening delimiter '/[a-zA-Z]/F', - [ - '[a-z]', //Array of Regexes - '[A-Z]', - '[0-9]', - ], '/[a-zA-Z]/', //Regex string ]; $subject = '1 2 a 3 4 b 5 6'; foreach ($regex_array as $regex_value) { - try { - var_dump(preg_split($regex_value, $subject)); - } catch (TypeError $e) { - echo $e::class, ': ', $e->getMessage(), "\n"; - } -} -$regex_value = new stdclass(); //Object -try { - var_dump(preg_split($regex_value, $subject)); -} catch (TypeError $e) { - echo $e::class, ': ', $e->getMessage(), "\n"; + var_dump(preg_split($regex_value, $subject)); } ?> --EXPECTF-- @@ -47,7 +32,6 @@ bool(false) Warning: preg_split(): Unknown modifier 'F' in %spreg_split_error1.php on line %d bool(false) -TypeError: preg_split(): Argument #1 ($pattern) must be of type string, array given array(3) { [0]=> string(4) "1 2 " @@ -56,4 +40,3 @@ array(3) { [2]=> string(4) " 5 6" } -TypeError: preg_split(): Argument #1 ($pattern) must be of type string, stdClass given From db4dfeef70bc5fe9805edafaf7e9f88973241f2d Mon Sep 17 00:00:00 2001 From: Gina Peter Banyard Date: Sat, 26 Sep 2026 13:31:42 +0100 Subject: [PATCH 4/7] pcre: add some tests for disabled PCRE features --- ext/pcre/tests/callout_syntax_in_pattern.phpt | 13 ++++++++++ .../tests/disabled_pcre_compile_options.phpt | 25 +++++++++++++++++++ 2 files changed, 38 insertions(+) create mode 100644 ext/pcre/tests/callout_syntax_in_pattern.phpt create mode 100644 ext/pcre/tests/disabled_pcre_compile_options.phpt diff --git a/ext/pcre/tests/callout_syntax_in_pattern.phpt b/ext/pcre/tests/callout_syntax_in_pattern.phpt new file mode 100644 index 000000000000..65ffe09d5f82 --- /dev/null +++ b/ext/pcre/tests/callout_syntax_in_pattern.phpt @@ -0,0 +1,13 @@ +--TEST-- +PCRE2 callout feature is not supported. +--FILE-- + +--EXPECT-- +int(0) diff --git a/ext/pcre/tests/disabled_pcre_compile_options.phpt b/ext/pcre/tests/disabled_pcre_compile_options.phpt new file mode 100644 index 000000000000..e3dc515167eb --- /dev/null +++ b/ext/pcre/tests/disabled_pcre_compile_options.phpt @@ -0,0 +1,25 @@ +--TEST-- +Disabled PCRE2 regex compilation features. +--FILE-- + +--EXPECTF-- +Warning: preg_match(): Compilation failed: PCRE2 does not support \F, \L, \l, \N{name}, \U, or \u at offset 2 in %s on line %d +bool(false) + +Warning: preg_match(): Compilation failed: using \C is incompatible with the 'u' modifier at offset 2 in %s on line %d +bool(false) + +Warning: preg_match(): Compilation failed: \K is not allowed in lookarounds (but see PCRE2_EXTRA_ALLOW_LOOKAROUND_BSK) at offset 8 in %s on line %d +bool(false) From 68e69a68c80d65a85bf19438befe8252fdb970ba Mon Sep 17 00:00:00 2001 From: Gina Peter Banyard Date: Sat, 26 Sep 2026 16:20:30 +0100 Subject: [PATCH 5/7] pcre: improve error message for \K in lookarounds --- ext/pcre/php_pcre.c | 13 +++++++++---- ext/pcre/tests/bug70345.phpt | 4 ++-- ext/pcre/tests/disabled_pcre_compile_options.phpt | 2 +- 3 files changed, 12 insertions(+), 7 deletions(-) diff --git a/ext/pcre/php_pcre.c b/ext/pcre/php_pcre.c index 7a11a6216391..88fc724983e3 100644 --- a/ext/pcre/php_pcre.c +++ b/ext/pcre/php_pcre.c @@ -779,10 +779,15 @@ PHPAPI pcre_cache_entry* pcre_get_compiled_regex_cache_ex(zend_string *regex, bo zend_string_release_ex(key, 0); } const char *err_msg = (const char*) error; - if (errnumber == PCRE2_ERROR_BACKSLASH_C_CALLER_DISABLED) { - err_msg = "using \\C is incompatible with the 'u' modifier"; - } else { - pcre2_get_error_message(errnumber, error, sizeof(error)); + switch (errnumber) { + case PCRE2_ERROR_BACKSLASH_K_IN_LOOKAROUND: + err_msg = "\\K is not allowed in lookarounds"; + break; + case PCRE2_ERROR_BACKSLASH_C_CALLER_DISABLED: + err_msg = "using \\C is incompatible with the 'u' modifier"; + break; + default: + pcre2_get_error_message(errnumber, error, sizeof(error)); } php_error_docref(NULL,E_WARNING, "Compilation failed: %s at offset %zu", err_msg, erroffset); pcre_handle_exec_error(PCRE2_ERROR_INTERNAL); diff --git a/ext/pcre/tests/bug70345.phpt b/ext/pcre/tests/bug70345.phpt index bdfa2041fc08..eee101a10e0e 100644 --- a/ext/pcre/tests/bug70345.phpt +++ b/ext/pcre/tests/bug70345.phpt @@ -19,8 +19,8 @@ preg_match($regex, $subject, $matches); var_dump($matches); ?> --EXPECTF-- -Warning: preg_split(): Compilation failed: \K is not allowed in lookarounds (but see PCRE2_EXTRA_ALLOW_LOOKAROUND_BSK) at offset 9 in %s on line %d +Warning: preg_split(): Compilation failed: \K is not allowed in lookarounds at offset 9 in %s on line %d bool(false) -Warning: preg_match(): Compilation failed: \K is not allowed in lookarounds (but see PCRE2_EXTRA_ALLOW_LOOKAROUND_BSK) at offset 12 in %s on line %d +Warning: preg_match(): Compilation failed: \K is not allowed in lookarounds at offset 12 in %s on line %d NULL diff --git a/ext/pcre/tests/disabled_pcre_compile_options.phpt b/ext/pcre/tests/disabled_pcre_compile_options.phpt index e3dc515167eb..c675ac7b6117 100644 --- a/ext/pcre/tests/disabled_pcre_compile_options.phpt +++ b/ext/pcre/tests/disabled_pcre_compile_options.phpt @@ -21,5 +21,5 @@ bool(false) Warning: preg_match(): Compilation failed: using \C is incompatible with the 'u' modifier at offset 2 in %s on line %d bool(false) -Warning: preg_match(): Compilation failed: \K is not allowed in lookarounds (but see PCRE2_EXTRA_ALLOW_LOOKAROUND_BSK) at offset 8 in %s on line %d +Warning: preg_match(): Compilation failed: \K is not allowed in lookarounds at offset 8 in %s on line %d bool(false) From 3d76c81438e9d848344c2df60cd2ef16005f60c8 Mon Sep 17 00:00:00 2001 From: Gina Peter Banyard Date: Sat, 26 Sep 2026 16:31:28 +0100 Subject: [PATCH 6/7] pcre: block callout syntax in pattern compilation if PCRE2 lib supports it --- ext/pcre/php_pcre.c | 4 ++++ ext/pcre/tests/bug75457.phpt | 6 ++++++ ext/pcre/tests/callout_syntax_in_pattern.phpt | 6 ++++++ .../callout_syntax_in_pattern_disabled.phpt | 20 +++++++++++++++++++ 4 files changed, 36 insertions(+) create mode 100644 ext/pcre/tests/callout_syntax_in_pattern_disabled.phpt diff --git a/ext/pcre/php_pcre.c b/ext/pcre/php_pcre.c index 88fc724983e3..f4a7b97413d1 100644 --- a/ext/pcre/php_pcre.c +++ b/ext/pcre/php_pcre.c @@ -577,7 +577,11 @@ PHPAPI pcre_cache_entry* pcre_get_compiled_regex_cache_ex(zend_string *regex, bo #else uint32_t coptions = 0; #endif +#if PCRE2_MAJOR >= 10 && PCRE2_MINOR >= 45 + uint32_t eoptions = PCRE2_EXTRA_NEVER_CALLOUT; +#else uint32_t eoptions = 0; +#endif PCRE2_UCHAR error[128]; PCRE2_SIZE erroffset; int errnumber; diff --git a/ext/pcre/tests/bug75457.phpt b/ext/pcre/tests/bug75457.phpt index 1401b25ff6fb..97adb7c66e92 100644 --- a/ext/pcre/tests/bug75457.phpt +++ b/ext/pcre/tests/bug75457.phpt @@ -1,5 +1,11 @@ --TEST-- Bug #75457 (heap-use-after-free in php7.0.25) +--SKIPIF-- += 10 && PCRE_VERSION_MINOR >= 45) { + die("skip callout feature is disable in PCRE2 10.45 and above"); +} +?> --FILE-- = 10 && PCRE_VERSION_MINOR >= 45) { + die("skip callout feature is disable in PCRE2 10.45 and above"); +} +?> --FILE-- = 10 && PCRE_VERSION_MINOR >= 45)) { + die("skip needs 10.45 or above"); +} +?> +--FILE-- + +--EXPECTF-- +Warning: preg_match(): Compilation failed: using callouts is disabled by the application at offset 4 in %s on line %d +bool(false) From 2aeffed1ba766dffd526e10ecd4ffca99dd2f28d Mon Sep 17 00:00:00 2001 From: Gina Peter Banyard Date: Sat, 26 Sep 2026 17:59:13 +0100 Subject: [PATCH 7/7] pcre: drop ifdef around PCRE2_UCP As far as I can tell this is always available. --- ext/pcre/php_pcre.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/ext/pcre/php_pcre.c b/ext/pcre/php_pcre.c index f4a7b97413d1..393315554861 100644 --- a/ext/pcre/php_pcre.c +++ b/ext/pcre/php_pcre.c @@ -722,9 +722,7 @@ PHPAPI pcre_cache_entry* pcre_get_compiled_regex_cache_ex(zend_string *regex, bo /* In PCRE, by default, \d, \D, \s, \S, \w, and \W recognize only ASCII characters, even in UTF-8 mode. However, this can be changed by setting the PCRE2_UCP option. */ -#ifdef PCRE2_UCP coptions |= PCRE2_UCP; -#endif /* The \C escape sequence is unsafe in PCRE2_UTF mode */ coptions |= PCRE2_NEVER_BACKSLASH_C; break;