diff --git a/ext/pcre/php_pcre.c b/ext/pcre/php_pcre.c index 04e5d858c34b4..d40876664455e 100644 --- a/ext/pcre/php_pcre.c +++ b/ext/pcre/php_pcre.c @@ -1028,7 +1028,7 @@ static inline void populate_match_value( static void populate_subpat_array( zval *subpats, char *subject, PCRE2_SIZE *offsets, zend_string **subpat_names, - int count, const PCRE2_SPTR mark, zend_long flags) { + uint32_t num_subpats, int count, const PCRE2_SPTR mark, zend_long flags) { zend_bool offset_capture = (flags & PREG_OFFSET_CAPTURE) != 0; zend_bool unmatched_as_null = (flags & PREG_UNMATCHED_AS_NULL) != 0; zval val; @@ -1040,6 +1040,11 @@ static void populate_subpat_array( offsets[(i<<1)+1] - offsets[i<<1], offsets[i<<1], subpat_names[i], unmatched_as_null); } + if (unmatched_as_null) { + for (i = count; i < num_subpats; i++) { + add_offset_pair(subpats, NULL, 0, PCRE2_UNSET, subpat_names[i], 1); + } + } } else { for (i = 0; i < count; i++) { populate_match_value( @@ -1050,6 +1055,15 @@ static void populate_subpat_array( } zend_hash_next_index_insert(Z_ARRVAL_P(subpats), &val); } + if (unmatched_as_null) { + for (i = count; i < num_subpats; i++) { + ZVAL_NULL(&val); + if (subpat_names[i]) { + zend_hash_update(Z_ARRVAL_P(subpats), subpat_names[i], &val); + } + zend_hash_next_index_insert(Z_ARRVAL_P(subpats), &val); + } + } } } else { if (offset_capture) { @@ -1058,12 +1072,22 @@ static void populate_subpat_array( offsets[(i<<1)+1] - offsets[i<<1], offsets[i<<1], NULL, unmatched_as_null); } + if (unmatched_as_null) { + for (i = count; i < num_subpats; i++) { + add_offset_pair(subpats, NULL, 0, PCRE2_UNSET, NULL, 1); + } + } } else { for (i = 0; i < count; i++) { populate_match_value( &val, subject, offsets[2*i], offsets[2*i+1], unmatched_as_null); zend_hash_next_index_insert(Z_ARRVAL_P(subpats), &val); } + if (unmatched_as_null) { + for (i = count; i < num_subpats; i++) { + add_next_index_null(subpats); + } + } } } /* Add MARK, if available */ @@ -1302,7 +1326,8 @@ PHPAPI void php_pcre_match_impl(pcre_cache_entry *pce, zend_string *subject_str, array_init_size(&result_set, count + (mark ? 1 : 0)); mark = pcre2_get_mark(match_data); populate_subpat_array( - &result_set, subject, offsets, subpat_names, count, mark, flags); + &result_set, subject, offsets, subpat_names, + num_subpats, count, mark, flags); /* And add it to the output array */ zend_hash_next_index_insert(Z_ARRVAL_P(subpats), &result_set); } @@ -1310,7 +1335,7 @@ PHPAPI void php_pcre_match_impl(pcre_cache_entry *pce, zend_string *subject_str, /* For each subpattern, insert it into the subpatterns array. */ mark = pcre2_get_mark(match_data); populate_subpat_array( - subpats, subject, offsets, subpat_names, count, mark, flags); + subpats, subject, offsets, subpat_names, num_subpats, count, mark, flags); break; } } @@ -1469,14 +1494,14 @@ static int preg_get_backref(char **str, int *backref) /* {{{ preg_do_repl_func */ -static zend_string *preg_do_repl_func(zend_fcall_info *fci, zend_fcall_info_cache *fcc, char *subject, PCRE2_SIZE *offsets, zend_string **subpat_names, int count, const PCRE2_SPTR mark, zend_long flags) +static zend_string *preg_do_repl_func(zend_fcall_info *fci, zend_fcall_info_cache *fcc, char *subject, PCRE2_SIZE *offsets, zend_string **subpat_names, uint32_t num_subpats, int count, const PCRE2_SPTR mark, zend_long flags) { zend_string *result_str; zval retval; /* Function return value */ zval arg; /* Argument to pass to function */ array_init_size(&arg, count + (mark ? 1 : 0)); - populate_subpat_array(&arg, subject, offsets, subpat_names, count, mark, flags); + populate_subpat_array(&arg, subject, offsets, subpat_names, num_subpats, count, mark, flags); fci->retval = &retval; fci->param_count = 1; @@ -1874,7 +1899,8 @@ static zend_string *php_pcre_replace_func_impl(pcre_cache_entry *pce, zend_strin new_len = result_len + offsets[0] - start_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, + eval_result = preg_do_repl_func( + fci, fcc, subject, offsets, subpat_names, num_subpats, count, pcre2_get_mark(match_data), flags); ZEND_ASSERT(eval_result); diff --git a/ext/pcre/tests/bug61780_1.phpt b/ext/pcre/tests/bug61780_1.phpt index dc5806cb30e40..6bbe3e436442b 100644 --- a/ext/pcre/tests/bug61780_1.phpt +++ b/ext/pcre/tests/bug61780_1.phpt @@ -125,6 +125,8 @@ array ( 0 => array ( 0 => '1', + 1 => NULL, + 2 => NULL, ), 1 => array ( @@ -136,10 +138,13 @@ array ( array ( 0 => '45', 1 => '4', + 2 => NULL, ), 3 => array ( 0 => '6', + 1 => NULL, + 2 => NULL, ), ) @@ -151,6 +156,16 @@ array ( 0 => '1', 1 => 0, ), + 1 => + array ( + 0 => NULL, + 1 => -1, + ), + 2 => + array ( + 0 => NULL, + 1 => -1, + ), ), 1 => array ( @@ -182,6 +197,11 @@ array ( 0 => '4', 1 => 3, ), + 2 => + array ( + 0 => NULL, + 1 => -1, + ), ), 3 => array ( @@ -190,5 +210,15 @@ array ( 0 => '6', 1 => 5, ), + 1 => + array ( + 0 => NULL, + 1 => -1, + ), + 2 => + array ( + 0 => NULL, + 1 => -1, + ), ), ) diff --git a/ext/pcre/tests/bug61780_2.phpt b/ext/pcre/tests/bug61780_2.phpt index faf44d368bef7..90462173519e7 100644 --- a/ext/pcre/tests/bug61780_2.phpt +++ b/ext/pcre/tests/bug61780_2.phpt @@ -177,6 +177,10 @@ array ( 0 => array ( 0 => '1', + 'a' => NULL, + 1 => NULL, + 'b' => NULL, + 2 => NULL, ), 1 => array ( @@ -191,10 +195,16 @@ array ( 0 => '45', 'a' => '4', 1 => '4', + 'b' => NULL, + 2 => NULL, ), 3 => array ( 0 => '6', + 'a' => NULL, + 1 => NULL, + 'b' => NULL, + 2 => NULL, ), ) @@ -206,6 +216,26 @@ array ( 0 => '1', 1 => 0, ), + 'a' => + array ( + 0 => NULL, + 1 => -1, + ), + 1 => + array ( + 0 => NULL, + 1 => -1, + ), + 'b' => + array ( + 0 => NULL, + 1 => -1, + ), + 2 => + array ( + 0 => NULL, + 1 => -1, + ), ), 1 => array ( @@ -252,6 +282,16 @@ array ( 0 => '4', 1 => 3, ), + 'b' => + array ( + 0 => NULL, + 1 => -1, + ), + 2 => + array ( + 0 => NULL, + 1 => -1, + ), ), 3 => array ( @@ -260,5 +300,25 @@ array ( 0 => '6', 1 => 5, ), + 'a' => + array ( + 0 => NULL, + 1 => -1, + ), + 1 => + array ( + 0 => NULL, + 1 => -1, + ), + 'b' => + array ( + 0 => NULL, + 1 => -1, + ), + 2 => + array ( + 0 => NULL, + 1 => -1, + ), ), ) diff --git a/ext/pcre/tests/preg_replace_callback_flags.phpt b/ext/pcre/tests/preg_replace_callback_flags.phpt index f85f9a53132a2..7e9a130ba754f 100644 --- a/ext/pcre/tests/preg_replace_callback_flags.phpt +++ b/ext/pcre/tests/preg_replace_callback_flags.phpt @@ -93,11 +93,13 @@ array(1) { } string(3) "abc" -array(2) { +array(3) { [0]=> string(1) "a" [1]=> string(1) "a" + [2]=> + NULL } array(3) { [0]=> @@ -109,11 +111,13 @@ array(3) { } string(3) "abc" -array(2) { +array(3) { [0]=> string(1) "a" [1]=> string(1) "a" + [2]=> + NULL } array(3) { [0]=>