]> granicus.if.org Git - php/commitdiff
Fixed bug #77193 Infinite loop in preg_replace_callback
authorAnatol Belski <ab@php.net>
Sat, 1 Dec 2018 09:24:06 +0000 (10:24 +0100)
committerAnatol Belski <ab@php.net>
Sat, 1 Dec 2018 09:24:06 +0000 (10:24 +0100)
Don't return preallocated match data more than once in nested calls.

ext/pcre/php_pcre.c
ext/pcre/tests/bug77193.phpt [new file with mode: 0644]

index 5165209b85d7adc00436ded22d242877c81761a0..ff86458fbfa98f0a0d212b04b198b8988bd2c848 100644 (file)
@@ -901,17 +901,21 @@ 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 (!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 (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) {
-               return mdata;
+               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);
@@ -919,8 +923,10 @@ PHPAPI pcre2_match_data *php_pcre_create_match_data(uint32_t capture_count, pcre
 
 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;
        }
 }/*}}}*/
 
diff --git a/ext/pcre/tests/bug77193.phpt b/ext/pcre/tests/bug77193.phpt
new file mode 100644 (file)
index 0000000..5dc7913
--- /dev/null
@@ -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===