mirror of
https://github.com/php/php-src.git
synced 2025-08-16 14:08:47 +02:00
commit
e30f52b919
3 changed files with 36 additions and 18 deletions
7
NEWS
7
NEWS
|
@ -1,5 +1,12 @@
|
||||||
PHP NEWS
|
PHP NEWS
|
||||||
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||
|
|
||||||
|
?? ??? ????, PHP 7.4.4
|
||||||
|
|
||||||
|
- PCRE:
|
||||||
|
. Fixed bug #79188 (Memory corruption in preg_replace/preg_replace_callback
|
||||||
|
and unicode). (Nikita)
|
||||||
|
|
||||||
?? ??? ????, PHP 7.4.3
|
?? ??? ????, PHP 7.4.3
|
||||||
|
|
||||||
- Core:
|
- Core:
|
||||||
|
|
|
@ -1582,6 +1582,7 @@ PHPAPI zend_string *php_pcre_replace_impl(pcre_cache_entry *pce, zend_string *su
|
||||||
size_t match_len; /* Length of the current match */
|
size_t match_len; /* Length of the current match */
|
||||||
int backref; /* Backreference number */
|
int backref; /* Backreference number */
|
||||||
PCRE2_SIZE start_offset; /* Where the new search starts */
|
PCRE2_SIZE start_offset; /* Where the new search starts */
|
||||||
|
size_t last_end_offset; /* Where the last search ended */
|
||||||
char *walkbuf, /* Location of current replacement in the result */
|
char *walkbuf, /* Location of current replacement in the result */
|
||||||
*walk, /* Used to walk the replacement string */
|
*walk, /* Used to walk the replacement string */
|
||||||
*match, /* The current match */
|
*match, /* The current match */
|
||||||
|
@ -1600,6 +1601,7 @@ PHPAPI zend_string *php_pcre_replace_impl(pcre_cache_entry *pce, zend_string *su
|
||||||
/* Initialize */
|
/* Initialize */
|
||||||
match = NULL;
|
match = NULL;
|
||||||
start_offset = 0;
|
start_offset = 0;
|
||||||
|
last_end_offset = 0;
|
||||||
result_len = 0;
|
result_len = 0;
|
||||||
PCRE_G(error_code) = PHP_PCRE_NO_ERROR;
|
PCRE_G(error_code) = PHP_PCRE_NO_ERROR;
|
||||||
|
|
||||||
|
@ -1626,7 +1628,7 @@ PHPAPI zend_string *php_pcre_replace_impl(pcre_cache_entry *pce, zend_string *su
|
||||||
options, match_data, mctx);
|
options, match_data, mctx);
|
||||||
|
|
||||||
while (1) {
|
while (1) {
|
||||||
piece = subject + start_offset;
|
piece = subject + last_end_offset;
|
||||||
|
|
||||||
if (count >= 0 && limit > 0) {
|
if (count >= 0 && limit > 0) {
|
||||||
zend_bool simple_string;
|
zend_bool simple_string;
|
||||||
|
@ -1656,7 +1658,7 @@ matched:
|
||||||
/* Set the match location in subject */
|
/* Set the match location in subject */
|
||||||
match = subject + offsets[0];
|
match = subject + offsets[0];
|
||||||
|
|
||||||
new_len = result_len + offsets[0] - start_offset; /* part before the match */
|
new_len = result_len + offsets[0] - last_end_offset; /* part before the match */
|
||||||
|
|
||||||
walk = ZSTR_VAL(replace_str);
|
walk = ZSTR_VAL(replace_str);
|
||||||
replace_end = walk + ZSTR_LEN(replace_str);
|
replace_end = walk + ZSTR_LEN(replace_str);
|
||||||
|
@ -1733,7 +1735,7 @@ matched:
|
||||||
limit--;
|
limit--;
|
||||||
|
|
||||||
/* Advance to the next piece. */
|
/* Advance to the next piece. */
|
||||||
start_offset = offsets[1];
|
start_offset = last_end_offset = offsets[1];
|
||||||
|
|
||||||
/* If we have matched an empty string, mimic what Perl's /g options does.
|
/* If we have matched an empty string, mimic what Perl's /g options does.
|
||||||
This turns out to be rather cunning. First we set PCRE2_NOTEMPTY_ATSTART and try
|
This turns out to be rather cunning. First we set PCRE2_NOTEMPTY_ATSTART and try
|
||||||
|
@ -1753,10 +1755,7 @@ matched:
|
||||||
to achieve this, unless we're already at the end of the string. */
|
to achieve this, unless we're already at the end of the string. */
|
||||||
if (start_offset < subject_len) {
|
if (start_offset < subject_len) {
|
||||||
size_t unit_len = calculate_unit_length(pce, piece);
|
size_t unit_len = calculate_unit_length(pce, piece);
|
||||||
|
|
||||||
start_offset += unit_len;
|
start_offset += unit_len;
|
||||||
memcpy(ZSTR_VAL(result) + result_len, piece, unit_len);
|
|
||||||
result_len += unit_len;
|
|
||||||
} else {
|
} else {
|
||||||
goto not_matched;
|
goto not_matched;
|
||||||
}
|
}
|
||||||
|
@ -1771,7 +1770,7 @@ not_matched:
|
||||||
result = zend_string_copy(subject_str);
|
result = zend_string_copy(subject_str);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
new_len = result_len + subject_len - start_offset;
|
new_len = result_len + subject_len - last_end_offset;
|
||||||
if (new_len >= alloc_len) {
|
if (new_len >= alloc_len) {
|
||||||
alloc_len = new_len; /* now we know exactly how long it is */
|
alloc_len = new_len; /* now we know exactly how long it is */
|
||||||
if (NULL != result) {
|
if (NULL != result) {
|
||||||
|
@ -1781,8 +1780,8 @@ not_matched:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/* stick that last bit of string on our output */
|
/* stick that last bit of string on our output */
|
||||||
memcpy(ZSTR_VAL(result) + result_len, piece, subject_len - start_offset);
|
memcpy(ZSTR_VAL(result) + result_len, piece, subject_len - last_end_offset);
|
||||||
result_len += subject_len - start_offset;
|
result_len += subject_len - last_end_offset;
|
||||||
ZSTR_VAL(result)[result_len] = '\0';
|
ZSTR_VAL(result)[result_len] = '\0';
|
||||||
ZSTR_LEN(result) = result_len;
|
ZSTR_LEN(result) = result_len;
|
||||||
break;
|
break;
|
||||||
|
@ -1824,6 +1823,7 @@ static zend_string *php_pcre_replace_func_impl(pcre_cache_entry *pce, zend_strin
|
||||||
size_t new_len; /* Length of needed storage */
|
size_t new_len; /* Length of needed storage */
|
||||||
size_t alloc_len; /* Actual allocated length */
|
size_t alloc_len; /* Actual allocated length */
|
||||||
PCRE2_SIZE start_offset; /* Where the new search starts */
|
PCRE2_SIZE start_offset; /* Where the new search starts */
|
||||||
|
size_t last_end_offset; /* Where the last search ended */
|
||||||
char *match, /* The current match */
|
char *match, /* The current match */
|
||||||
*piece; /* The current piece of subject */
|
*piece; /* The current piece of subject */
|
||||||
size_t result_len; /* Length of result */
|
size_t result_len; /* Length of result */
|
||||||
|
@ -1853,6 +1853,7 @@ static zend_string *php_pcre_replace_func_impl(pcre_cache_entry *pce, zend_strin
|
||||||
/* Initialize */
|
/* Initialize */
|
||||||
match = NULL;
|
match = NULL;
|
||||||
start_offset = 0;
|
start_offset = 0;
|
||||||
|
last_end_offset = 0;
|
||||||
result_len = 0;
|
result_len = 0;
|
||||||
PCRE_G(error_code) = PHP_PCRE_NO_ERROR;
|
PCRE_G(error_code) = PHP_PCRE_NO_ERROR;
|
||||||
|
|
||||||
|
@ -1885,7 +1886,7 @@ static zend_string *php_pcre_replace_func_impl(pcre_cache_entry *pce, zend_strin
|
||||||
options, match_data, mctx);
|
options, match_data, mctx);
|
||||||
|
|
||||||
while (1) {
|
while (1) {
|
||||||
piece = subject + start_offset;
|
piece = subject + last_end_offset;
|
||||||
|
|
||||||
if (count >= 0 && limit) {
|
if (count >= 0 && limit) {
|
||||||
/* Check for too many substrings condition. */
|
/* Check for too many substrings condition. */
|
||||||
|
@ -1913,7 +1914,7 @@ matched:
|
||||||
/* Set the match location in subject */
|
/* Set the match location in subject */
|
||||||
match = subject + offsets[0];
|
match = subject + offsets[0];
|
||||||
|
|
||||||
new_len = result_len + offsets[0] - start_offset; /* part before the match */
|
new_len = result_len + offsets[0] - last_end_offset; /* part before the match */
|
||||||
|
|
||||||
/* Use custom function to get replacement string and its length. */
|
/* Use custom function to get replacement string and its length. */
|
||||||
eval_result = preg_do_repl_func(
|
eval_result = preg_do_repl_func(
|
||||||
|
@ -1945,7 +1946,7 @@ matched:
|
||||||
limit--;
|
limit--;
|
||||||
|
|
||||||
/* Advance to the next piece. */
|
/* Advance to the next piece. */
|
||||||
start_offset = offsets[1];
|
start_offset = last_end_offset = offsets[1];
|
||||||
|
|
||||||
/* If we have matched an empty string, mimic what Perl's /g options does.
|
/* If we have matched an empty string, mimic what Perl's /g options does.
|
||||||
This turns out to be rather cunning. First we set PCRE2_NOTEMPTY_ATSTART and try
|
This turns out to be rather cunning. First we set PCRE2_NOTEMPTY_ATSTART and try
|
||||||
|
@ -1965,10 +1966,7 @@ matched:
|
||||||
to achieve this, unless we're already at the end of the string. */
|
to achieve this, unless we're already at the end of the string. */
|
||||||
if (start_offset < subject_len) {
|
if (start_offset < subject_len) {
|
||||||
size_t unit_len = calculate_unit_length(pce, piece);
|
size_t unit_len = calculate_unit_length(pce, piece);
|
||||||
|
|
||||||
start_offset += unit_len;
|
start_offset += unit_len;
|
||||||
memcpy(ZSTR_VAL(result) + result_len, piece, unit_len);
|
|
||||||
result_len += unit_len;
|
|
||||||
} else {
|
} else {
|
||||||
goto not_matched;
|
goto not_matched;
|
||||||
}
|
}
|
||||||
|
@ -1983,7 +1981,7 @@ not_matched:
|
||||||
result = zend_string_copy(subject_str);
|
result = zend_string_copy(subject_str);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
new_len = result_len + subject_len - start_offset;
|
new_len = result_len + subject_len - last_end_offset;
|
||||||
if (new_len >= alloc_len) {
|
if (new_len >= alloc_len) {
|
||||||
alloc_len = new_len; /* now we know exactly how long it is */
|
alloc_len = new_len; /* now we know exactly how long it is */
|
||||||
if (NULL != result) {
|
if (NULL != result) {
|
||||||
|
@ -1993,8 +1991,8 @@ not_matched:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/* stick that last bit of string on our output */
|
/* stick that last bit of string on our output */
|
||||||
memcpy(ZSTR_VAL(result) + result_len, piece, subject_len - start_offset);
|
memcpy(ZSTR_VAL(result) + result_len, piece, subject_len - last_end_offset);
|
||||||
result_len += subject_len - start_offset;
|
result_len += subject_len - last_end_offset;
|
||||||
ZSTR_VAL(result)[result_len] = '\0';
|
ZSTR_VAL(result)[result_len] = '\0';
|
||||||
ZSTR_LEN(result) = result_len;
|
ZSTR_LEN(result) = result_len;
|
||||||
break;
|
break;
|
||||||
|
|
13
ext/pcre/tests/bug79188.phpt
Normal file
13
ext/pcre/tests/bug79188.phpt
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
--TEST--
|
||||||
|
Bug #79188: Memory corruption in preg_replace/preg_replace_callback and unicode
|
||||||
|
--FILE--
|
||||||
|
<?php
|
||||||
|
|
||||||
|
var_dump(preg_replace("//u", "", "a" . str_repeat("\u{1f612}", 10)));
|
||||||
|
var_dump(preg_replace_callback(
|
||||||
|
"//u", function() { return ""; }, "a" . str_repeat("\u{1f612}", 10)));
|
||||||
|
|
||||||
|
?>
|
||||||
|
--EXPECT--
|
||||||
|
string(41) "a😒😒😒😒😒😒😒😒😒😒"
|
||||||
|
string(41) "a😒😒😒😒😒😒😒😒😒😒"
|
Loading…
Add table
Add a link
Reference in a new issue