summaryrefslogtreecommitdiff
path: root/ext/pcre/php_pcre.c
diff options
context:
space:
mode:
authorNikita Popov <nikita.ppv@gmail.com>2020-02-05 11:19:55 +0100
committerNikita Popov <nikita.ppv@gmail.com>2020-02-05 11:21:25 +0100
commite30f52b919e04d3a057b6759e7d66c01da550bf8 (patch)
treef5e923ebdcf2ad8a597c93350af7b73b4bab690b /ext/pcre/php_pcre.c
parentd9f51e0e498abfb79fe23296f3761153ffce0c66 (diff)
parent13bfa9f5ac04a65300cf20211e2e3314e827595d (diff)
downloadphp-git-e30f52b919e04d3a057b6759e7d66c01da550bf8.tar.gz
Merge branch 'PHP-7.3' into PHP-7.4
* PHP-7.3: Fixed bug #79188
Diffstat (limited to 'ext/pcre/php_pcre.c')
-rw-r--r--ext/pcre/php_pcre.c34
1 files changed, 16 insertions, 18 deletions
diff --git a/ext/pcre/php_pcre.c b/ext/pcre/php_pcre.c
index 15afc29778..481d564f66 100644
--- a/ext/pcre/php_pcre.c
+++ b/ext/pcre/php_pcre.c
@@ -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 */
int backref; /* Backreference number */
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 */
*walk, /* Used to walk the replacement string */
*match, /* The current match */
@@ -1600,6 +1601,7 @@ PHPAPI zend_string *php_pcre_replace_impl(pcre_cache_entry *pce, zend_string *su
/* Initialize */
match = NULL;
start_offset = 0;
+ last_end_offset = 0;
result_len = 0;
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);
while (1) {
- piece = subject + start_offset;
+ piece = subject + last_end_offset;
if (count >= 0 && limit > 0) {
zend_bool simple_string;
@@ -1656,7 +1658,7 @@ matched:
/* Set the match location in subject */
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);
replace_end = walk + ZSTR_LEN(replace_str);
@@ -1733,7 +1735,7 @@ matched:
limit--;
/* 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.
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. */
if (start_offset < subject_len) {
size_t unit_len = calculate_unit_length(pce, piece);
-
start_offset += unit_len;
- memcpy(ZSTR_VAL(result) + result_len, piece, unit_len);
- result_len += unit_len;
} else {
goto not_matched;
}
@@ -1771,7 +1770,7 @@ not_matched:
result = zend_string_copy(subject_str);
break;
}
- new_len = result_len + subject_len - start_offset;
+ new_len = result_len + subject_len - last_end_offset;
if (new_len >= alloc_len) {
alloc_len = new_len; /* now we know exactly how long it is */
if (NULL != result) {
@@ -1781,8 +1780,8 @@ not_matched:
}
}
/* stick that last bit of string on our output */
- memcpy(ZSTR_VAL(result) + result_len, piece, subject_len - start_offset);
- result_len += subject_len - start_offset;
+ memcpy(ZSTR_VAL(result) + result_len, piece, subject_len - last_end_offset);
+ result_len += subject_len - last_end_offset;
ZSTR_VAL(result)[result_len] = '\0';
ZSTR_LEN(result) = result_len;
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 alloc_len; /* Actual allocated length */
PCRE2_SIZE start_offset; /* Where the new search starts */
+ size_t last_end_offset; /* Where the last search ended */
char *match, /* The current match */
*piece; /* The current piece of subject */
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 */
match = NULL;
start_offset = 0;
+ last_end_offset = 0;
result_len = 0;
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);
while (1) {
- piece = subject + start_offset;
+ piece = subject + last_end_offset;
if (count >= 0 && limit) {
/* Check for too many substrings condition. */
@@ -1913,7 +1914,7 @@ matched:
/* Set the match location in subject */
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. */
eval_result = preg_do_repl_func(
@@ -1945,7 +1946,7 @@ matched:
limit--;
/* 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.
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. */
if (start_offset < subject_len) {
size_t unit_len = calculate_unit_length(pce, piece);
-
start_offset += unit_len;
- memcpy(ZSTR_VAL(result) + result_len, piece, unit_len);
- result_len += unit_len;
} else {
goto not_matched;
}
@@ -1983,7 +1981,7 @@ not_matched:
result = zend_string_copy(subject_str);
break;
}
- new_len = result_len + subject_len - start_offset;
+ new_len = result_len + subject_len - last_end_offset;
if (new_len >= alloc_len) {
alloc_len = new_len; /* now we know exactly how long it is */
if (NULL != result) {
@@ -1993,8 +1991,8 @@ not_matched:
}
}
/* stick that last bit of string on our output */
- memcpy(ZSTR_VAL(result) + result_len, piece, subject_len - start_offset);
- result_len += subject_len - start_offset;
+ memcpy(ZSTR_VAL(result) + result_len, piece, subject_len - last_end_offset);
+ result_len += subject_len - last_end_offset;
ZSTR_VAL(result)[result_len] = '\0';
ZSTR_LEN(result) = result_len;
break;