mirror of
https://github.com/php/php-src.git
synced 2025-08-16 05:58:45 +02:00
Fixed bug #73483 (Segmentation fault on pcre_replace_callback)
This commit is contained in:
parent
274951a4a2
commit
ebfd93f725
3 changed files with 84 additions and 35 deletions
7
NEWS
7
NEWS
|
@ -17,9 +17,9 @@ PHP NEWS
|
|||
This may be enabled again using envirionment variable USE_ZEND_DTRACE=1.
|
||||
(Dmitry)
|
||||
|
||||
- Mysqlnd:
|
||||
. Fixed bug #64526 (Add missing mysqlnd.* parameters to php.ini-*). (cmb)
|
||||
|
||||
- Mysqlnd:
|
||||
. Fixed bug #64526 (Add missing mysqlnd.* parameters to php.ini-*). (cmb)
|
||||
|
||||
- ODBC:
|
||||
. Fixed bug #73448 (odbc_errormsg returns trash, always 513 bytes).
|
||||
(Anatol)
|
||||
|
@ -29,6 +29,7 @@ PHP NEWS
|
|||
. Fixed bug #73546 (Logging for opcache has an empty file name). (mhagstrand)
|
||||
|
||||
- PCRE:
|
||||
. Fixed bug #73483 (Segmentation fault on pcre_replace_callback). (Laruence)
|
||||
. Fixed bug #73392 (A use-after-free in zend allocator management).
|
||||
(Laruence)
|
||||
|
||||
|
|
|
@ -114,9 +114,6 @@ static void php_free_pcre_cache(zval *data) /* {{{ */
|
|||
}
|
||||
#if HAVE_SETLOCALE
|
||||
if ((void*)pce->tables) pefree((void*)pce->tables, 1);
|
||||
if (pce->locale) {
|
||||
zend_string_release(pce->locale);
|
||||
}
|
||||
#endif
|
||||
pefree(pce, 1);
|
||||
}
|
||||
|
@ -320,27 +317,30 @@ PHPAPI pcre_cache_entry* pcre_get_compiled_regex_cache(zend_string *regex)
|
|||
pcre_cache_entry *pce;
|
||||
pcre_cache_entry new_entry;
|
||||
int rc;
|
||||
zend_string *key;
|
||||
|
||||
#if HAVE_SETLOCALE
|
||||
if (BG(locale_string) &&
|
||||
(ZSTR_LEN(BG(locale_string)) != 1 && ZSTR_VAL(BG(locale_string))[0] != 'C')) {
|
||||
key = zend_string_alloc(ZSTR_LEN(regex) + ZSTR_LEN(BG(locale_string)) + 1, 0);
|
||||
memcpy(ZSTR_VAL(key), ZSTR_VAL(BG(locale_string)), ZSTR_LEN(BG(locale_string)) + 1);
|
||||
memcpy(ZSTR_VAL(key) + ZSTR_LEN(BG(locale_string)), ZSTR_VAL(regex), ZSTR_LEN(regex) + 1);
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
key = regex;
|
||||
}
|
||||
|
||||
/* Try to lookup the cached regex entry, and if successful, just pass
|
||||
back the compiled pattern, otherwise go on and compile it. */
|
||||
pce = zend_hash_find_ptr(&PCRE_G(pcre_cache), regex);
|
||||
pce = zend_hash_find_ptr(&PCRE_G(pcre_cache), key);
|
||||
if (pce) {
|
||||
#if HAVE_SETLOCALE
|
||||
if (pce->locale == BG(locale_string) ||
|
||||
(pce->locale && BG(locale_string) &&
|
||||
ZSTR_LEN(pce->locale) == ZSTR_LEN(BG(locale_string)) &&
|
||||
!memcmp(ZSTR_VAL(pce->locale), ZSTR_VAL(BG(locale_string)), ZSTR_LEN(pce->locale))) ||
|
||||
(!pce->locale &&
|
||||
ZSTR_LEN(BG(locale_string)) == 1 &&
|
||||
ZSTR_VAL(BG(locale_string))[0] == 'C') ||
|
||||
(!BG(locale_string) &&
|
||||
ZSTR_LEN(pce->locale) == 1 &&
|
||||
ZSTR_VAL(pce->locale)[0] == 'C')) {
|
||||
return pce;
|
||||
if (key != regex) {
|
||||
zend_string_release(key);
|
||||
}
|
||||
#else
|
||||
return pce;
|
||||
#endif
|
||||
return pce;
|
||||
}
|
||||
|
||||
p = ZSTR_VAL(regex);
|
||||
|
@ -349,6 +349,11 @@ PHPAPI pcre_cache_entry* pcre_get_compiled_regex_cache(zend_string *regex)
|
|||
get to the end without encountering a delimiter. */
|
||||
while (isspace((int)*(unsigned char *)p)) p++;
|
||||
if (*p == 0) {
|
||||
#if HAVE_SETLOCALE
|
||||
if (key != regex) {
|
||||
zend_string_release(key);
|
||||
}
|
||||
#endif
|
||||
php_error_docref(NULL, E_WARNING,
|
||||
p < ZSTR_VAL(regex) + ZSTR_LEN(regex) ? "Null byte in regex" : "Empty regular expression");
|
||||
return NULL;
|
||||
|
@ -358,6 +363,11 @@ PHPAPI pcre_cache_entry* pcre_get_compiled_regex_cache(zend_string *regex)
|
|||
or a backslash. */
|
||||
delimiter = *p++;
|
||||
if (isalnum((int)*(unsigned char *)&delimiter) || delimiter == '\\') {
|
||||
#if HAVE_SETLOCALE
|
||||
if (key != regex) {
|
||||
zend_string_release(key);
|
||||
}
|
||||
#endif
|
||||
php_error_docref(NULL,E_WARNING, "Delimiter must not be alphanumeric or backslash");
|
||||
return NULL;
|
||||
}
|
||||
|
@ -397,6 +407,11 @@ PHPAPI pcre_cache_entry* pcre_get_compiled_regex_cache(zend_string *regex)
|
|||
}
|
||||
|
||||
if (*pp == 0) {
|
||||
#if HAVE_SETLOCALE
|
||||
if (key != regex) {
|
||||
zend_string_release(key);
|
||||
}
|
||||
#endif
|
||||
if (pp < ZSTR_VAL(regex) + ZSTR_LEN(regex)) {
|
||||
php_error_docref(NULL,E_WARNING, "Null byte in regex");
|
||||
} else if (start_delimiter == end_delimiter) {
|
||||
|
@ -453,13 +468,17 @@ PHPAPI pcre_cache_entry* pcre_get_compiled_regex_cache(zend_string *regex)
|
|||
php_error_docref(NULL,E_WARNING, "Null byte in regex");
|
||||
}
|
||||
efree(pattern);
|
||||
#if HAVE_SETLOCALE
|
||||
if (key != regex) {
|
||||
zend_string_release(key);
|
||||
}
|
||||
#endif
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
#if HAVE_SETLOCALE
|
||||
if (BG(locale_string) &&
|
||||
(ZSTR_LEN(BG(locale_string)) != 1 || ZSTR_VAL(BG(locale_string))[0] != 'C')) {
|
||||
if (key != regex) {
|
||||
tables = pcre_maketables();
|
||||
}
|
||||
#endif
|
||||
|
@ -472,6 +491,11 @@ PHPAPI pcre_cache_entry* pcre_get_compiled_regex_cache(zend_string *regex)
|
|||
tables);
|
||||
|
||||
if (re == NULL) {
|
||||
#if HAVE_SETLOCALE
|
||||
if (key != regex) {
|
||||
zend_string_release(key);
|
||||
}
|
||||
#endif
|
||||
php_error_docref(NULL,E_WARNING, "Compilation failed: %s at offset %d", error, erroffset);
|
||||
efree(pattern);
|
||||
if (tables) {
|
||||
|
@ -516,7 +540,7 @@ PHPAPI pcre_cache_entry* pcre_get_compiled_regex_cache(zend_string *regex)
|
|||
* these are supposedly the oldest ones (but not necessarily the least used
|
||||
* ones).
|
||||
*/
|
||||
if (zend_hash_num_elements(&PCRE_G(pcre_cache)) == PCRE_CACHE_SIZE) {
|
||||
if (!pce && zend_hash_num_elements(&PCRE_G(pcre_cache)) == PCRE_CACHE_SIZE) {
|
||||
int num_clean = PCRE_CACHE_SIZE / 8;
|
||||
zend_hash_apply_with_argument(&PCRE_G(pcre_cache), pcre_clean_cache, &num_clean);
|
||||
}
|
||||
|
@ -527,23 +551,29 @@ PHPAPI pcre_cache_entry* pcre_get_compiled_regex_cache(zend_string *regex)
|
|||
new_entry.preg_options = poptions;
|
||||
new_entry.compile_options = coptions;
|
||||
#if HAVE_SETLOCALE
|
||||
new_entry.locale = BG(locale_string) ?
|
||||
((GC_FLAGS(BG(locale_string)) & IS_STR_PERSISTENT) ?
|
||||
zend_string_copy(BG(locale_string)) :
|
||||
zend_string_init(ZSTR_VAL(BG(locale_string)), ZSTR_LEN(BG(locale_string)), 1)) :
|
||||
NULL;
|
||||
new_entry.locale = 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) {
|
||||
#if HAVE_SETLOCALE
|
||||
if (key != regex) {
|
||||
zend_string_release(key);
|
||||
}
|
||||
#endif
|
||||
php_error_docref(NULL, E_WARNING, "Internal pcre_fullinfo() error %d", rc);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
rc = pcre_fullinfo(re, extra, PCRE_INFO_NAMECOUNT, &new_entry.name_count);
|
||||
if (rc < 0) {
|
||||
#if HAVE_SETLOCALE
|
||||
if (key != regex) {
|
||||
zend_string_release(key);
|
||||
}
|
||||
#endif
|
||||
php_error_docref(NULL, E_WARNING, "Internal pcre_fullinfo() error %d", rc);
|
||||
return NULL;
|
||||
}
|
||||
|
@ -556,15 +586,18 @@ PHPAPI pcre_cache_entry* pcre_get_compiled_regex_cache(zend_string *regex)
|
|||
* as hash keys especually for this table.
|
||||
* See bug #63180
|
||||
*/
|
||||
if (!ZSTR_IS_INTERNED(regex) || !(GC_FLAGS(regex) & IS_STR_PERMANENT)) {
|
||||
zend_string *str = zend_string_init(ZSTR_VAL(regex), ZSTR_LEN(regex), 1);
|
||||
GC_REFCOUNT(str) = 0; /* will be incremented by zend_hash_update_mem() */
|
||||
ZSTR_H(str) = ZSTR_H(regex);
|
||||
regex = str;
|
||||
if (!ZSTR_IS_INTERNED(key) || !(GC_FLAGS(key) & IS_STR_PERMANENT)) {
|
||||
pce = zend_hash_str_update_mem(&PCRE_G(pcre_cache),
|
||||
ZSTR_VAL(key), ZSTR_LEN(key), &new_entry, sizeof(pcre_cache_entry));
|
||||
#if HAVE_SETLOCALE
|
||||
if (key != regex) {
|
||||
zend_string_release(key);
|
||||
}
|
||||
#endif
|
||||
} else {
|
||||
pce = zend_hash_update_mem(&PCRE_G(pcre_cache), key, &new_entry, sizeof(pcre_cache_entry));
|
||||
}
|
||||
|
||||
pce = zend_hash_update_mem(&PCRE_G(pcre_cache), regex, &new_entry, sizeof(pcre_cache_entry));
|
||||
|
||||
return pce;
|
||||
}
|
||||
/* }}} */
|
||||
|
|
15
ext/pcre/tests/bug73483.phpt
Normal file
15
ext/pcre/tests/bug73483.phpt
Normal file
|
@ -0,0 +1,15 @@
|
|||
--TEST--
|
||||
Bug #73483 (Segmentation fault on pcre_replace_callback)
|
||||
--FILE--
|
||||
<?php
|
||||
$regex = "#dummy#";
|
||||
setlocale(LC_ALL, "C");
|
||||
var_dump(preg_replace_callback($regex, function (array $matches) use($regex) {
|
||||
setlocale(LC_ALL, "en_US");
|
||||
$ret = preg_replace($regex, "okey", $matches[0]);
|
||||
setlocale(LC_ALL, "C");
|
||||
return $ret;
|
||||
}, "dummy"));
|
||||
?>
|
||||
--EXPECT--
|
||||
string(4) "okey"
|
Loading…
Add table
Add a link
Reference in a new issue