@@ -1641,6 +1641,13 @@ PHPAPI zend_string *php_pcre_replace_impl(pcre_cache_entry *pce, zend_string *su
16411641 }
16421642 }
16431643
1644+ const bool count_changes = (flags & PREG_REPLACE_COUNT_CHANGES ) != 0 ;
1645+ size_t local_replace_count = 0 ;
1646+ size_t * replace_count_ptr = replace_count ;
1647+ if (count_changes && replace_count ) {
1648+ replace_count_ptr = & local_replace_count ;
1649+ }
1650+
16441651 options = (pce -> compile_options & PCRE2_UTF ) ? 0 : PCRE2_NO_UTF_CHECK ;
16451652
16461653 /* Array of subpattern offsets */
@@ -1769,14 +1776,14 @@ PHPAPI zend_string *php_pcre_replace_impl(pcre_cache_entry *pce, zend_string *su
17691776 result_len += (walkbuf - (ZSTR_VAL (result ) + result_len ));
17701777 }
17711778
1772- if (replace_count ) {
1779+ if (replace_count_ptr ) {
17731780 bool count_changes = flags & PREG_REPLACE_COUNT_CHANGES ;
17741781 if (!count_changes ) {
1775- ++ * replace_count ;
1782+ ++ * replace_count_ptr ;
17761783 } else {
17771784 if (rep_len != match_len_local ||
17781785 (match_len_local && memcmp (rep_ptr , match , match_len_local ) != 0 )) {
1779- ++ * replace_count ;
1786+ ++ * replace_count_ptr ;
17801787 }
17811788 }
17821789 }
@@ -1855,6 +1862,15 @@ PHPAPI zend_string *php_pcre_replace_impl(pcre_cache_entry *pce, zend_string *su
18551862 pcre2_match_data_free (match_data );
18561863 }
18571864
1865+ if (count_changes && replace_count && result != NULL ) {
1866+ /* If the final output is identical to the input, no effective changes happened. */
1867+ if (ZSTR_LEN (result ) == subject_len
1868+ && (subject_len == 0 || memcmp (ZSTR_VAL (result ), subject , subject_len ) == 0 )) {
1869+ local_replace_count = 0 ;
1870+ }
1871+ * replace_count += local_replace_count ;
1872+ }
1873+
18581874 return result ;
18591875}
18601876/* }}} */
@@ -1913,6 +1929,13 @@ static zend_string *php_pcre_replace_func_impl(pcre_cache_entry *pce, zend_strin
19131929
19141930 options = (pce -> compile_options & PCRE2_UTF ) ? 0 : PCRE2_NO_UTF_CHECK ;
19151931
1932+ const bool count_changes = (flags & PREG_REPLACE_COUNT_CHANGES ) != 0 ;
1933+ size_t local_replace_count = 0 ;
1934+ size_t * replace_count_ptr = replace_count ;
1935+ if (count_changes && replace_count ) {
1936+ replace_count_ptr = & local_replace_count ;
1937+ }
1938+
19161939 /* Array of subpattern offsets */
19171940 PCRE2_SIZE * const offsets = pcre2_get_ovector_pointer (match_data );
19181941
@@ -1961,15 +1984,14 @@ static zend_string *php_pcre_replace_func_impl(pcre_cache_entry *pce, zend_strin
19611984 goto error ;
19621985 }
19631986
1964- if (replace_count ) {
1965- zend_long count_changes = flags & PREG_REPLACE_COUNT_CHANGES ;
1987+ if (replace_count_ptr ) {
19661988 if (!count_changes ) {
1967- ++ * replace_count ;
1989+ ++ * replace_count_ptr ;
19681990 } else {
19691991 size_t match_len = (size_t )(offsets [1 ] - offsets [0 ]);
19701992 if (ZSTR_LEN (eval_result ) != match_len ||
19711993 (match_len && memcmp (ZSTR_VAL (eval_result ), match , match_len ) != 0 )) {
1972- ++ * replace_count ;
1994+ ++ * replace_count_ptr ;
19731995 }
19741996 }
19751997 }
@@ -2066,6 +2088,16 @@ static zend_string *php_pcre_replace_func_impl(pcre_cache_entry *pce, zend_strin
20662088 }
20672089 mdata_used = old_mdata_used ;
20682090
2091+ if (count_changes && replace_count && result != NULL ) {
2092+ /* If the final output is identical to the input, no effective changes happened. */
2093+ if (ZSTR_LEN (result ) == ZSTR_LEN (subject_str )
2094+ && (ZSTR_LEN (subject_str ) == 0
2095+ || memcmp (ZSTR_VAL (result ), ZSTR_VAL (subject_str ), ZSTR_LEN (subject_str )) == 0 )) {
2096+ local_replace_count = 0 ;
2097+ }
2098+ * replace_count += local_replace_count ;
2099+ }
2100+
20692101 return result ;
20702102}
20712103
0 commit comments