diff options
author | Nikita Popov <nikita.ppv@gmail.com> | 2020-02-11 17:30:59 +0100 |
---|---|---|
committer | Nikita Popov <nikita.ppv@gmail.com> | 2020-02-11 17:31:48 +0100 |
commit | 3a515309631fcacd80ee1f6e247965a0c4626786 (patch) | |
tree | adddb23e8f7c2d9032648c2f084cdf51658bb893 | |
parent | 93b183ed551999e8c3f80cff1cc40c2be5f33033 (diff) | |
download | php-git-3a515309631fcacd80ee1f6e247965a0c4626786.tar.gz |
Fixed bug #79257
Replace an existing entry for a given name only if we have a match.
-rw-r--r-- | NEWS | 2 | ||||
-rw-r--r-- | ext/pcre/php_pcre.c | 22 | ||||
-rw-r--r-- | ext/pcre/tests/bug79257.phpt | 218 |
3 files changed, 237 insertions, 5 deletions
@@ -21,6 +21,8 @@ PHP NEWS . Fixed bug #79188 (Memory corruption in preg_replace/preg_replace_callback and unicode). (Nikita) . Fixed bug #79241 (Segmentation fault on preg_match()). (Nikita) + . Fixed bug #79257 (Duplicate named groups (?J) prefer last alternative even + if not matched). (Nikita) - Standard: . Fixed bug #79254 (getenv() w/o arguments not showing changes). (cmb) diff --git a/ext/pcre/php_pcre.c b/ext/pcre/php_pcre.c index c50bd2fba2..39896bb07b 100644 --- a/ext/pcre/php_pcre.c +++ b/ext/pcre/php_pcre.c @@ -995,6 +995,20 @@ static inline void populate_match_value( } } +static inline void add_named( + zval *subpats, zend_string *name, zval *val, zend_bool unmatched) { + /* If the DUPNAMES option is used, multiple subpatterns might have the same name. + * In this case we want to preserve the one that actually has a value. */ + if (!unmatched) { + zend_hash_update(Z_ARRVAL_P(subpats), name, val); + } else { + if (!zend_hash_add(Z_ARRVAL_P(subpats), name, val)) { + return; + } + } + Z_TRY_ADDREF_P(val); +} + /* {{{ add_offset_pair */ static inline void add_offset_pair( zval *result, const char *subject, PCRE2_SIZE start_offset, PCRE2_SIZE end_offset, @@ -1023,8 +1037,7 @@ static inline void add_offset_pair( } if (name) { - Z_ADDREF(match_pair); - zend_hash_update(Z_ARRVAL_P(result), name, &match_pair); + add_named(result, name, &match_pair, start_offset == PCRE2_UNSET); } zend_hash_next_index_insert(Z_ARRVAL_P(result), &match_pair); } @@ -1054,8 +1067,7 @@ static void populate_subpat_array( populate_match_value( &val, subject, offsets[2*i], offsets[2*i+1], unmatched_as_null); if (subpat_names[i]) { - Z_TRY_ADDREF(val); - zend_hash_update(Z_ARRVAL_P(subpats), subpat_names[i], &val); + add_named(subpats, subpat_names[i], &val, offsets[2*i] == PCRE2_UNSET); } zend_hash_next_index_insert(Z_ARRVAL_P(subpats), &val); } @@ -1063,7 +1075,7 @@ static void populate_subpat_array( 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_add(Z_ARRVAL_P(subpats), subpat_names[i], &val); } zend_hash_next_index_insert(Z_ARRVAL_P(subpats), &val); } diff --git a/ext/pcre/tests/bug79257.phpt b/ext/pcre/tests/bug79257.phpt new file mode 100644 index 0000000000..b52a0d6574 --- /dev/null +++ b/ext/pcre/tests/bug79257.phpt @@ -0,0 +1,218 @@ +--TEST-- +Bug #79257: Duplicate named groups (?J) prefer last alternative even if not matched +--FILE-- +<?php + +preg_match('/(?J)(?:(?<g>foo)|(?<g>bar))/', 'foo', $matches); +var_dump($matches); +preg_match('/(?J)(?:(?<g>foo)|(?<g>bar))/', 'foo', $matches, + PREG_UNMATCHED_AS_NULL); +var_dump($matches); +preg_match('/(?J)(?:(?<g>foo)|(?<g>bar))/', 'foo', $matches, + PREG_OFFSET_CAPTURE); +var_dump($matches); +preg_match('/(?J)(?:(?<g>foo)|(?<g>bar))/', 'foo', $matches, + PREG_UNMATCHED_AS_NULL|PREG_OFFSET_CAPTURE); +var_dump($matches); + +preg_match('/(?J)(?:(?<g>foo)|(?<g>bar))(?<h>baz)/', 'foobaz', $matches); +var_dump($matches); +preg_match('/(?J)(?:(?<g>foo)|(?<g>bar))(?<h>baz)/', 'foobaz', $matches, + PREG_UNMATCHED_AS_NULL); +var_dump($matches); +preg_match('/(?J)(?:(?<g>foo)|(?<g>bar))(?<h>baz)/', 'foobaz', $matches, + PREG_OFFSET_CAPTURE); +var_dump($matches); +preg_match('/(?J)(?:(?<g>foo)|(?<g>bar))(?<h>baz)/', 'foobaz', $matches, + PREG_UNMATCHED_AS_NULL|PREG_OFFSET_CAPTURE); +var_dump($matches); + +?> +--EXPECT-- +array(3) { + [0]=> + string(3) "foo" + ["g"]=> + string(3) "foo" + [1]=> + string(3) "foo" +} +array(4) { + [0]=> + string(3) "foo" + ["g"]=> + string(3) "foo" + [1]=> + string(3) "foo" + [2]=> + NULL +} +array(3) { + [0]=> + array(2) { + [0]=> + string(3) "foo" + [1]=> + int(0) + } + ["g"]=> + array(2) { + [0]=> + string(3) "foo" + [1]=> + int(0) + } + [1]=> + array(2) { + [0]=> + string(3) "foo" + [1]=> + int(0) + } +} +array(4) { + [0]=> + array(2) { + [0]=> + string(3) "foo" + [1]=> + int(0) + } + ["g"]=> + array(2) { + [0]=> + string(3) "foo" + [1]=> + int(0) + } + [1]=> + array(2) { + [0]=> + string(3) "foo" + [1]=> + int(0) + } + [2]=> + array(2) { + [0]=> + NULL + [1]=> + int(-1) + } +} +array(6) { + [0]=> + string(6) "foobaz" + ["g"]=> + string(3) "foo" + [1]=> + string(3) "foo" + [2]=> + string(0) "" + ["h"]=> + string(3) "baz" + [3]=> + string(3) "baz" +} +array(6) { + [0]=> + string(6) "foobaz" + ["g"]=> + string(3) "foo" + [1]=> + string(3) "foo" + [2]=> + NULL + ["h"]=> + string(3) "baz" + [3]=> + string(3) "baz" +} +array(6) { + [0]=> + array(2) { + [0]=> + string(6) "foobaz" + [1]=> + int(0) + } + ["g"]=> + array(2) { + [0]=> + string(3) "foo" + [1]=> + int(0) + } + [1]=> + array(2) { + [0]=> + string(3) "foo" + [1]=> + int(0) + } + [2]=> + array(2) { + [0]=> + string(0) "" + [1]=> + int(-1) + } + ["h"]=> + array(2) { + [0]=> + string(3) "baz" + [1]=> + int(3) + } + [3]=> + array(2) { + [0]=> + string(3) "baz" + [1]=> + int(3) + } +} +array(6) { + [0]=> + array(2) { + [0]=> + string(6) "foobaz" + [1]=> + int(0) + } + ["g"]=> + array(2) { + [0]=> + string(3) "foo" + [1]=> + int(0) + } + [1]=> + array(2) { + [0]=> + string(3) "foo" + [1]=> + int(0) + } + [2]=> + array(2) { + [0]=> + NULL + [1]=> + int(-1) + } + ["h"]=> + array(2) { + [0]=> + string(3) "baz" + [1]=> + int(3) + } + [3]=> + array(2) { + [0]=> + string(3) "baz" + [1]=> + int(3) + } +} |