diff options
author | Nikita Popov <nikita.ppv@gmail.com> | 2020-01-29 10:57:44 +0100 |
---|---|---|
committer | Nikita Popov <nikita.ppv@gmail.com> | 2020-02-05 11:18:46 +0100 |
commit | 13bfa9f5ac04a65300cf20211e2e3314e827595d (patch) | |
tree | 773a2ff524a4f8553a7131fcde7e0b72bc6576c1 /ext/pcre/php_pcre.c | |
parent | e3632fdc0d1fded7c88ee7d46cba26af55c3c07b (diff) | |
download | php-git-13bfa9f5ac04a65300cf20211e2e3314e827595d.tar.gz |
Fixed bug #79188
Diffstat (limited to 'ext/pcre/php_pcre.c')
-rw-r--r-- | ext/pcre/php_pcre.c | 34 |
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; |