php.net | support | documentation | report a bug | advanced search | search howto | statistics | random bug | login | |
Patch pcre-refcount for PCRE related Bug #69864Patch version 2015-06-18 12:49 UTC Return to Bug #69864 | Download this patchThis patch renders other patches obsolete Obsolete patches: Patch Revisions:Developer: cmb@php.netext/pcre/php_pcre.c | 22 +++++++++++++++++----- ext/pcre/tests/bug69864.phpt | 36 ++++++++++++++++++++++++++++++++++++ 2 files changed, 53 insertions(+), 5 deletions(-) diff --git a/ext/pcre/php_pcre.c b/ext/pcre/php_pcre.c index c3ceb44..4ac85cc 100644 --- a/ext/pcre/php_pcre.c +++ b/ext/pcre/php_pcre.c @@ -187,13 +187,15 @@ static PHP_MSHUTDOWN_FUNCTION(pcre) /* {{{ static pcre_clean_cache */ static int pcre_clean_cache(zval *data, void *arg) { + /* data is not a zval, but rather a pcre_cache_entry** in PHP 7 */ + pcre_cache_entry *pce = *((pcre_cache_entry **) data); int *num_clean = (int *)arg; - if (*num_clean > 0) { + if (*num_clean > 0 && !pce->refcount) { (*num_clean)--; - return 1; + return ZEND_HASH_APPLY_REMOVE; } else { - return 0; + return ZEND_HASH_APPLY_KEEP; } } /* }}} */ @@ -461,6 +463,7 @@ PHPAPI pcre_cache_entry* pcre_get_compiled_regex_cache(zend_string *regex) NULL; new_entry.tables = tables; #endif + new_entry.refcount = 0; rc = pcre_fullinfo(re, extra, PCRE_INFO_CAPTURECOUNT, &new_entry.capture_count); if (rc < 0) { @@ -584,8 +587,10 @@ static void php_do_pcre_match(INTERNAL_FUNCTION_PARAMETERS, int global) /* {{{ * RETURN_FALSE; } + pce->refcount++; php_pcre_match_impl(pce, subject->val, (int)subject->len, return_value, subpats, global, ZEND_NUM_ARGS() >= 4, flags, start_offset); + pce->refcount--; } /* }}} */ @@ -1017,14 +1022,17 @@ PHPAPI zend_string *php_pcre_replace(zend_string *regex, int limit, int *replace_count) { pcre_cache_entry *pce; /* Compiled regular expression */ + zend_string *result; /* Function result */ /* Compile regex or get it from cache. */ if ((pce = pcre_get_compiled_regex_cache(regex)) == NULL) { return NULL; } - - return php_pcre_replace_impl(pce, subject_str, subject, subject_len, replace_val, + pce->refcount++; + result = php_pcre_replace_impl(pce, subject_str, subject, subject_len, replace_val, is_callable_replace, limit, replace_count); + pce->refcount--; + return result; } /* }}} */ @@ -1643,7 +1651,9 @@ static PHP_FUNCTION(preg_split) RETURN_FALSE; } + pce->refcount++; php_pcre_split_impl(pce, subject->val, (int)subject->len, return_value, (int)limit_val, flags); + pce->refcount--; } /* }}} */ @@ -1950,7 +1960,9 @@ static PHP_FUNCTION(preg_grep) RETURN_FALSE; } + pce->refcount++; php_pcre_grep_impl(pce, input, return_value, flags); + pce->refcount--; } /* }}} */ diff --git a/ext/pcre/tests/bug69864.phpt b/ext/pcre/tests/bug69864.phpt new file mode 100644 index 0000000..124ece5 --- /dev/null +++ b/ext/pcre/tests/bug69864.phpt @@ -0,0 +1,36 @@ +--TEST-- +Bug #69864 (Segfault in preg_replace_callback) +--FILE-- +<?php +const PREG_CACHE_SIZE = 4096; // this has to be >= the resp. constant in php_pcre.c + +var_dump(preg_replace_callback('/a/', function($m) { + for ($i = 0; $i < PREG_CACHE_SIZE; $i++) { + preg_match('/foo' . $i . 'bar/', '???foo' . $i . 'bar???'); + } + return 'b'; +}, 'aa')); +var_dump(preg_replace_callback('/a/', function($m) { + for ($i = 0; $i < PREG_CACHE_SIZE; $i++) { + preg_replace('/foo' . $i . 'bar/', 'baz', '???foo' . $i . 'bar???'); + } + return 'b'; +}, 'aa')); +var_dump(preg_replace_callback('/a/', function($m) { + for ($i = 0; $i < PREG_CACHE_SIZE; $i++) { + preg_split('/foo' . $i . 'bar/', '???foo' . $i . 'bar???'); + } + return 'b'; +}, 'aa')); +var_dump(preg_replace_callback('/a/', function($m) { + for ($i = 0; $i < PREG_CACHE_SIZE; $i++) { + preg_grep('/foo' . $i . 'bar/', ['???foo' . $i . 'bar???']); + } + return 'b'; +}, 'aa')); +?> +--EXPECT-- +string(2) "bb" +string(2) "bb" +string(2) "bb" +string(2) "bb" |
Copyright © 2001-2024 The PHP Group All rights reserved. |
Last updated: Thu Nov 21 15:01:30 2024 UTC |