Skip to content

Commit bc47f10

Browse files
committed
Merge branch 'PHP-5.5' into PHP-5.6
* PHP-5.5: updated NEWS Fixed bug #69864 (Segfault in preg_replace_callback)
2 parents 3e1aabb + 75b2ce2 commit bc47f10

File tree

2 files changed

+54
-6
lines changed

2 files changed

+54
-6
lines changed

ext/pcre/php_pcre.c

Lines changed: 18 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -169,13 +169,14 @@ static PHP_MSHUTDOWN_FUNCTION(pcre)
169169
/* {{{ static pcre_clean_cache */
170170
static int pcre_clean_cache(void *data, void *arg TSRMLS_DC)
171171
{
172+
pcre_cache_entry *pce = (pcre_cache_entry *) data;
172173
int *num_clean = (int *)arg;
173174

174-
if (*num_clean > 0) {
175+
if (*num_clean > 0 && !pce->refcount) {
175176
(*num_clean)--;
176-
return 1;
177+
return ZEND_HASH_APPLY_REMOVE;
177178
} else {
178-
return 0;
179+
return ZEND_HASH_APPLY_KEEP;
179180
}
180181
}
181182
/* }}} */
@@ -446,6 +447,7 @@ PHPAPI pcre_cache_entry* pcre_get_compiled_regex_cache(char *regex, int regex_le
446447
new_entry.locale = pestrdup(locale, 1);
447448
new_entry.tables = tables;
448449
#endif
450+
new_entry.refcount = 0;
449451

450452
/*
451453
* Interned strings are not duplicated when stored in HashTable,
@@ -550,8 +552,10 @@ static void php_do_pcre_match(INTERNAL_FUNCTION_PARAMETERS, int global) /* {{{ *
550552
RETURN_FALSE;
551553
}
552554

555+
pce->refcount++;
553556
php_pcre_match_impl(pce, subject, subject_len, return_value, subpats,
554557
global, ZEND_NUM_ARGS() >= 4, flags, start_offset TSRMLS_CC);
558+
pce->refcount--;
555559
}
556560
/* }}} */
557561

@@ -1017,14 +1021,18 @@ PHPAPI char *php_pcre_replace(char *regex, int regex_len,
10171021
int *result_len, int limit, int *replace_count TSRMLS_DC)
10181022
{
10191023
pcre_cache_entry *pce; /* Compiled regular expression */
1024+
char *result; /* Function result */
10201025

10211026
/* Compile regex or get it from cache. */
10221027
if ((pce = pcre_get_compiled_regex_cache(regex, regex_len TSRMLS_CC)) == NULL) {
10231028
return NULL;
10241029
}
1025-
1026-
return php_pcre_replace_impl(pce, subject, subject_len, replace_val,
1030+
pce->refcount++;
1031+
result = php_pcre_replace_impl(pce, subject, subject_len, replace_val,
10271032
is_callable_replace, result_len, limit, replace_count TSRMLS_CC);
1033+
pce->refcount--;
1034+
1035+
return result;
10281036
}
10291037
/* }}} */
10301038

@@ -1511,7 +1519,9 @@ static PHP_FUNCTION(preg_split)
15111519
RETURN_FALSE;
15121520
}
15131521

1522+
pce->refcount++;
15141523
php_pcre_split_impl(pce, subject, subject_len, return_value, limit_val, flags TSRMLS_CC);
1524+
pce->refcount--;
15151525
}
15161526
/* }}} */
15171527

@@ -1794,8 +1804,10 @@ static PHP_FUNCTION(preg_grep)
17941804
if ((pce = pcre_get_compiled_regex_cache(regex, regex_len TSRMLS_CC)) == NULL) {
17951805
RETURN_FALSE;
17961806
}
1797-
1807+
1808+
pce->refcount++;
17981809
php_pcre_grep_impl(pce, input, return_value, flags TSRMLS_CC);
1810+
pce->refcount--;
17991811
}
18001812
/* }}} */
18011813

ext/pcre/tests/bug69864.phpt

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
--TEST--
2+
Bug #69864 (Segfault in preg_replace_callback)
3+
--FILE--
4+
<?php
5+
const PREG_CACHE_SIZE = 4096; // this has to be >= the resp. constant in php_pcre.c
6+
7+
var_dump(preg_replace_callback('/a/', function($m) {
8+
for ($i = 0; $i < PREG_CACHE_SIZE; $i++) {
9+
preg_match('/foo' . $i . 'bar/', '???foo' . $i . 'bar???');
10+
}
11+
return 'b';
12+
}, 'aa'));
13+
var_dump(preg_replace_callback('/a/', function($m) {
14+
for ($i = 0; $i < PREG_CACHE_SIZE; $i++) {
15+
preg_replace('/foo' . $i . 'bar/', 'baz', '???foo' . $i . 'bar???');
16+
}
17+
return 'b';
18+
}, 'aa'));
19+
var_dump(preg_replace_callback('/a/', function($m) {
20+
for ($i = 0; $i < PREG_CACHE_SIZE; $i++) {
21+
preg_split('/foo' . $i . 'bar/', '???foo' . $i . 'bar???');
22+
}
23+
return 'b';
24+
}, 'aa'));
25+
var_dump(preg_replace_callback('/a/', function($m) {
26+
for ($i = 0; $i < PREG_CACHE_SIZE; $i++) {
27+
preg_grep('/foo' . $i . 'bar/', ['???foo' . $i . 'bar???']);
28+
}
29+
return 'b';
30+
}, 'aa'));
31+
?>
32+
--EXPECT--
33+
string(2) "bb"
34+
string(2) "bb"
35+
string(2) "bb"
36+
string(2) "bb"

0 commit comments

Comments
 (0)