@@ -1561,6 +1561,7 @@ PHPAPI zend_string *php_pcre_replace_impl(pcre_cache_entry *pce, zend_string *su
15611561 size_t match_len ; /* Length of the current match */
15621562 int backref ; /* Backreference number */
15631563 PCRE2_SIZE start_offset ; /* Where the new search starts */
1564+ size_t last_end_offset ; /* Where the last search ended */
15641565 char * walkbuf , /* Location of current replacement in the result */
15651566 * walk , /* Used to walk the replacement string */
15661567 * match , /* The current match */
@@ -1579,6 +1580,7 @@ PHPAPI zend_string *php_pcre_replace_impl(pcre_cache_entry *pce, zend_string *su
15791580 /* Initialize */
15801581 match = NULL ;
15811582 start_offset = 0 ;
1583+ last_end_offset = 0 ;
15821584 result_len = 0 ;
15831585 PCRE_G (error_code ) = PHP_PCRE_NO_ERROR ;
15841586
@@ -1605,7 +1607,7 @@ PHPAPI zend_string *php_pcre_replace_impl(pcre_cache_entry *pce, zend_string *su
16051607 options , match_data , mctx );
16061608
16071609 while (1 ) {
1608- piece = subject + start_offset ;
1610+ piece = subject + last_end_offset ;
16091611
16101612 if (count >= 0 && limit > 0 ) {
16111613 zend_bool simple_string ;
@@ -1635,7 +1637,7 @@ PHPAPI zend_string *php_pcre_replace_impl(pcre_cache_entry *pce, zend_string *su
16351637 /* Set the match location in subject */
16361638 match = subject + offsets [0 ];
16371639
1638- new_len = result_len + offsets [0 ] - start_offset ; /* part before the match */
1640+ new_len = result_len + offsets [0 ] - last_end_offset ; /* part before the match */
16391641
16401642 walk = ZSTR_VAL (replace_str );
16411643 replace_end = walk + ZSTR_LEN (replace_str );
@@ -1712,7 +1714,7 @@ PHPAPI zend_string *php_pcre_replace_impl(pcre_cache_entry *pce, zend_string *su
17121714 limit -- ;
17131715
17141716 /* Advance to the next piece. */
1715- start_offset = offsets [1 ];
1717+ start_offset = last_end_offset = offsets [1 ];
17161718
17171719 /* If we have matched an empty string, mimic what Perl's /g options does.
17181720 This turns out to be rather cunning. First we set PCRE2_NOTEMPTY_ATSTART and try
@@ -1732,10 +1734,7 @@ PHPAPI zend_string *php_pcre_replace_impl(pcre_cache_entry *pce, zend_string *su
17321734 to achieve this, unless we're already at the end of the string. */
17331735 if (start_offset < subject_len ) {
17341736 size_t unit_len = calculate_unit_length (pce , piece );
1735-
17361737 start_offset += unit_len ;
1737- memcpy (ZSTR_VAL (result ) + result_len , piece , unit_len );
1738- result_len += unit_len ;
17391738 } else {
17401739 goto not_matched ;
17411740 }
@@ -1750,7 +1749,7 @@ PHPAPI zend_string *php_pcre_replace_impl(pcre_cache_entry *pce, zend_string *su
17501749 result = zend_string_copy (subject_str );
17511750 break ;
17521751 }
1753- new_len = result_len + subject_len - start_offset ;
1752+ new_len = result_len + subject_len - last_end_offset ;
17541753 if (new_len >= alloc_len ) {
17551754 alloc_len = new_len ; /* now we know exactly how long it is */
17561755 if (NULL != result ) {
@@ -1760,8 +1759,8 @@ PHPAPI zend_string *php_pcre_replace_impl(pcre_cache_entry *pce, zend_string *su
17601759 }
17611760 }
17621761 /* stick that last bit of string on our output */
1763- memcpy (ZSTR_VAL (result ) + result_len , piece , subject_len - start_offset );
1764- result_len += subject_len - start_offset ;
1762+ memcpy (ZSTR_VAL (result ) + result_len , piece , subject_len - last_end_offset );
1763+ result_len += subject_len - last_end_offset ;
17651764 ZSTR_VAL (result )[result_len ] = '\0' ;
17661765 ZSTR_LEN (result ) = result_len ;
17671766 break ;
@@ -1803,6 +1802,7 @@ static zend_string *php_pcre_replace_func_impl(pcre_cache_entry *pce, zend_strin
18031802 size_t new_len ; /* Length of needed storage */
18041803 size_t alloc_len ; /* Actual allocated length */
18051804 PCRE2_SIZE start_offset ; /* Where the new search starts */
1805+ size_t last_end_offset ; /* Where the last search ended */
18061806 char * match , /* The current match */
18071807 * piece ; /* The current piece of subject */
18081808 size_t result_len ; /* Length of result */
@@ -1832,6 +1832,7 @@ static zend_string *php_pcre_replace_func_impl(pcre_cache_entry *pce, zend_strin
18321832 /* Initialize */
18331833 match = NULL ;
18341834 start_offset = 0 ;
1835+ last_end_offset = 0 ;
18351836 result_len = 0 ;
18361837 PCRE_G (error_code ) = PHP_PCRE_NO_ERROR ;
18371838
@@ -1864,7 +1865,7 @@ static zend_string *php_pcre_replace_func_impl(pcre_cache_entry *pce, zend_strin
18641865 options , match_data , mctx );
18651866
18661867 while (1 ) {
1867- piece = subject + start_offset ;
1868+ piece = subject + last_end_offset ;
18681869
18691870 if (count >= 0 && limit ) {
18701871 /* Check for too many substrings condition. */
@@ -1892,7 +1893,7 @@ static zend_string *php_pcre_replace_func_impl(pcre_cache_entry *pce, zend_strin
18921893 /* Set the match location in subject */
18931894 match = subject + offsets [0 ];
18941895
1895- new_len = result_len + offsets [0 ] - start_offset ; /* part before the match */
1896+ new_len = result_len + offsets [0 ] - last_end_offset ; /* part before the match */
18961897
18971898 /* Use custom function to get replacement string and its length. */
18981899 eval_result = preg_do_repl_func (
@@ -1924,7 +1925,7 @@ static zend_string *php_pcre_replace_func_impl(pcre_cache_entry *pce, zend_strin
19241925 limit -- ;
19251926
19261927 /* Advance to the next piece. */
1927- start_offset = offsets [1 ];
1928+ start_offset = last_end_offset = offsets [1 ];
19281929
19291930 /* If we have matched an empty string, mimic what Perl's /g options does.
19301931 This turns out to be rather cunning. First we set PCRE2_NOTEMPTY_ATSTART and try
@@ -1944,10 +1945,7 @@ static zend_string *php_pcre_replace_func_impl(pcre_cache_entry *pce, zend_strin
19441945 to achieve this, unless we're already at the end of the string. */
19451946 if (start_offset < subject_len ) {
19461947 size_t unit_len = calculate_unit_length (pce , piece );
1947-
19481948 start_offset += unit_len ;
1949- memcpy (ZSTR_VAL (result ) + result_len , piece , unit_len );
1950- result_len += unit_len ;
19511949 } else {
19521950 goto not_matched ;
19531951 }
@@ -1962,7 +1960,7 @@ static zend_string *php_pcre_replace_func_impl(pcre_cache_entry *pce, zend_strin
19621960 result = zend_string_copy (subject_str );
19631961 break ;
19641962 }
1965- new_len = result_len + subject_len - start_offset ;
1963+ new_len = result_len + subject_len - last_end_offset ;
19661964 if (new_len >= alloc_len ) {
19671965 alloc_len = new_len ; /* now we know exactly how long it is */
19681966 if (NULL != result ) {
@@ -1972,8 +1970,8 @@ static zend_string *php_pcre_replace_func_impl(pcre_cache_entry *pce, zend_strin
19721970 }
19731971 }
19741972 /* stick that last bit of string on our output */
1975- memcpy (ZSTR_VAL (result ) + result_len , piece , subject_len - start_offset );
1976- result_len += subject_len - start_offset ;
1973+ memcpy (ZSTR_VAL (result ) + result_len , piece , subject_len - last_end_offset );
1974+ result_len += subject_len - last_end_offset ;
19771975 ZSTR_VAL (result )[result_len ] = '\0' ;
19781976 ZSTR_LEN (result ) = result_len ;
19791977 break ;
0 commit comments