Commit 0a03d105939 for php.net
commit 0a03d10593956e9cba57571194763830d08bdbb7
Author: Ilia Alshanetsky <ilia@ilia.ws>
Date: Tue May 12 17:40:10 2026 -0400
ext/pcre: fix duplicate MARK key in matches array
When a named capture group is also called "MARK" and the pattern uses
the (*MARK:name) directive, populate_subpat_array() inserted two
buckets with the same string key into the matches array.
zend_hash_str_add_new skips the duplicate-key check, so the named
capture's MARK and the directive's MARK both landed in the table.
Switch to zend_hash_str_update so the directive's value overwrites
the capture's value, restoring the behavior that existed via
add_assoc_string_ex before d6cc31cf9538.
Closes GH-22029
diff --git a/ext/pcre/php_pcre.c b/ext/pcre/php_pcre.c
index b9f8e1211ff..6a62d9717e7 100644
--- a/ext/pcre/php_pcre.c
+++ b/ext/pcre/php_pcre.c
@@ -1079,7 +1079,7 @@ static void populate_subpat_array(
/* Add MARK, if available */
if (mark) {
ZVAL_STRING(&val, (char *)mark);
- zend_hash_str_add_new(subpats_ht, ZEND_STRL("MARK"), &val);
+ zend_hash_str_update(subpats_ht, ZEND_STRL("MARK"), &val);
}
}
diff --git a/ext/pcre/tests/mark_named_collision.phpt b/ext/pcre/tests/mark_named_collision.phpt
new file mode 100644
index 00000000000..b644c4d4402
--- /dev/null
+++ b/ext/pcre/tests/mark_named_collision.phpt
@@ -0,0 +1,15 @@
+--TEST--
+preg_match: (*MARK:name) directive does not collide with named group called MARK
+--FILE--
+<?php
+preg_match('/(?P<MARK>[abc])(*MARK:value)/', "abc", $m);
+echo "count: ", count($m), "\n";
+echo "MARK: ", $m['MARK'], "\n";
+echo "json: ", json_encode($m), "\n";
+echo "keys: ", implode(',', array_keys($m)), "\n";
+?>
+--EXPECT--
+count: 3
+MARK: value
+json: {"0":"a","MARK":"value","1":"a"}
+keys: 0,MARK,1