summaryrefslogtreecommitdiff
path: root/ext/pcre/php_pcre.c
diff options
context:
space:
mode:
authorNikita Popov <nikita.ppv@gmail.com>2020-01-29 10:57:44 +0100
committerNikita Popov <nikita.ppv@gmail.com>2020-02-05 11:18:46 +0100
commit13bfa9f5ac04a65300cf20211e2e3314e827595d (patch)
tree773a2ff524a4f8553a7131fcde7e0b72bc6576c1 /ext/pcre/php_pcre.c
parente3632fdc0d1fded7c88ee7d46cba26af55c3c07b (diff)
downloadphp-git-13bfa9f5ac04a65300cf20211e2e3314e827595d.tar.gz
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 38eabe2556..decaa0e108 100644
--- a/ext/pcre/php_pcre.c
+++ b/ext/pcre/php_pcre.c
@@ -1574,6 +1574,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 */
@@ -1592,6 +1593,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;
@@ -1618,7 +1620,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;
@@ -1648,7 +1650,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);
@@ -1725,7 +1727,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
@@ -1745,10 +1747,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;
}
@@ -1763,7 +1762,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) {
@@ -1773,8 +1772,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;
@@ -1816,6 +1815,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 */
@@ -1845,6 +1845,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;
@@ -1877,7 +1878,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. */
@@ -1905,7 +1906,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(fci, fcc, subject, offsets, subpat_names, count,
@@ -1936,7 +1937,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
@@ -1956,10 +1957,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;
}
@@ -1974,7 +1972,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) {
@@ -1984,8 +1982,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;