Fixed bug #77193 Infinite loop in preg_replace_callback

Don't return preallocated match data more than once in nested calls.
This commit is contained in:
Anatol Belski 2018-12-01 10:24:06 +01:00
parent 471eb0dd95
commit ef1269d5c1
2 changed files with 41 additions and 8 deletions

View File

@ -901,26 +901,32 @@ PHPAPI pcre2_code* pcre_get_compiled_regex_ex(zend_string *regex, uint32_t *capt
required, perhaps just a minimum sized data would suffice. */
PHPAPI pcre2_match_data *php_pcre_create_match_data(uint32_t capture_count, pcre2_code *re)
{/*{{{*/
int rc = 0;
assert(NULL != re);
if (EXPECTED(!mdata_used)) {
int rc = 0;
if (!capture_count) {
/* As we deal with a non cached pattern, no other way to gather this info. */
rc = pcre2_pattern_info(re, PCRE2_INFO_CAPTURECOUNT, &capture_count);
}
if (rc >= 0 && capture_count + 1 <= PHP_PCRE_PREALLOC_MDATA_SIZE) {
mdata_used = 1;
return mdata;
}
}
return pcre2_match_data_create_from_pattern(re, gctx);
}/*}}}*/
PHPAPI void php_pcre_free_match_data(pcre2_match_data *match_data)
{/*{{{*/
if (match_data != mdata) {
if (UNEXPECTED(match_data != mdata)) {
pcre2_match_data_free(match_data);
} else {
mdata_used = 0;
}
}/*}}}*/

View File

@ -0,0 +1,27 @@
--TEST--
Bug #77193 Infinite loop in preg_replace_callback
--SKIPIF--
<?php
if (!extension_loaded("filter")) {
die("skip need filter extension");
}
?>
--FILE--
<?php
$text = '{CCM:CID_2}';
echo '1';
$mt = array();
preg_replace_callback(
'/([0-9]+)/i',
function ($matches) {
echo $matches[1];
filter_var('http', FILTER_VALIDATE_REGEXP, ['options' => ['regexp' => '/^http$/i']]);
},
$text
);
echo '3', "\n";
?>
===DONE===
--EXPECT--
123
===DONE===