[php-src] PHP-8.4: Forbid \C in UTF-8 patterns (#21139)

Arnaud Le Blanc via GitHub <[email protected]> Mon, 27 Jul 2026 16:01:37 +0000
Newsgroups gmane.comp.php.cvs.general
Message-ID <[email protected]>
Author: Arnaud Le Blanc (arnaud-lb)
Committer: GitHub (web-flow)
Pusher: arnaud-lb
Date: 2026-07-27T18:01:34+02:00

Commit: https://github.com/php/php-src/commit/1b091dcf37544e3f871db57e97e224371d85ec8d
Raw diff: https://github.com/php/php-src/commit/1b091dcf37544e3f871db57e97e224371d85ec8d.diff

Forbid \C in UTF-8 patterns (#21139)

Fixes GH-21134

Changed paths:
  A  ext/pcre/tests/gh21134.phpt
  M  NEWS
  M  ext/pcre/php_pcre.c


Diff:

diff --git a/NEWS b/NEWS
index 0aa44c4d5006..1dc666e361b5 100644
--- a/NEWS
+++ b/NEWS
@@ -16,6 +16,10 @@ PHP                                                                        NEWS
   . Fixed bug GH-22779 (mb_strrpos() returns the wrong position for a negative
     offset in a non-UTF-8 encoding). (Eyüp Can Akman)
 
+- PCRE:
+  . Fixed bug GH-21134 (Crash with \C + UTF-8). Using \C in UTF-8 patterns is
+    now forbidden. (Arnaud)
+
 - Sockets:
   . Fixed various memory related issues in ext/sockets. (David Carlier)
 
diff --git a/ext/pcre/php_pcre.c b/ext/pcre/php_pcre.c
index 43cee3b6b57e..6a24691a170e 100644
--- a/ext/pcre/php_pcre.c
+++ b/ext/pcre/php_pcre.c
@@ -734,6 +734,8 @@ PHPAPI pcre_cache_entry* pcre_get_compiled_regex_cache_ex(zend_string *regex, bo
 #ifdef PCRE2_UCP
 						coptions |= PCRE2_UCP;
 #endif
+						/* The \C escape sequence is unsafe in PCRE2_UTF mode */
+						coptions |= PCRE2_NEVER_BACKSLASH_C;
 				break;
 			case 'J':	coptions |= PCRE2_DUPNAMES;		break;
 
@@ -787,8 +789,13 @@ PHPAPI pcre_cache_entry* pcre_get_compiled_regex_cache_ex(zend_string *regex, bo
 		if (key != regex) {
 			zend_string_release_ex(key, 0);
 		}
-		pcre2_get_error_message(errnumber, error, sizeof(error));
-		php_error_docref(NULL,E_WARNING, "Compilation failed: %s at offset %zu", error, erroffset);
+		const char *err_msg = (const char*) error;
+		if (errnumber == PCRE2_ERROR_BACKSLASH_C_CALLER_DISABLED) {
+			err_msg = "using \\C is incompatible with the 'u' modifier";
+		} else {
+			pcre2_get_error_message(errnumber, error, sizeof(error));
+		}
+		php_error_docref(NULL,E_WARNING, "Compilation failed: %s at offset %zu", err_msg, erroffset);
 		pcre_handle_exec_error(PCRE2_ERROR_INTERNAL);
 		efree(pattern);
 		return NULL;
diff --git a/ext/pcre/tests/gh21134.phpt b/ext/pcre/tests/gh21134.phpt
new file mode 100644
index 000000000000..ddcf19a6e7a2
--- /dev/null
+++ b/ext/pcre/tests/gh21134.phpt
@@ -0,0 +1,15 @@
+--TEST--
+GH-21134: ASan negative-size-param in preg_match_all() with \C + UTF-8 multibyte input
+--CREDITS--
+vi3tL0u1s
+--FILE--
+<?php
+
+$r = preg_match_all("/(.*)\\C/u", "à", $m);
+var_dump($r, $m);
+
+?>
+--EXPECTF--
+Warning: preg_match_all(): Compilation failed: using \C is incompatible with the 'u' modifier at offset 6 in %s on line %d
+bool(false)
+NULL