From ec5a1e001db8455d89bc22d38d9dfd5bd17c0041 Mon Sep 17 00:00:00 2001 From: Ilija Tovilo Date: Mon, 23 Feb 2026 22:25:10 +0100 Subject: [PATCH 1/3] Fix preloaded constant erroneously propagated to file-cached script Since GH-15021 preloaded constants are propagated to compiled scripts. This is problematic for file cache, which assumes all referenced zvals are either persistently allocated or local to the current script. However, preloaded constants live in shm as immutable, but not persistent. To solve this, we'd need to duplicate propagated constants in the optimizer when file cache is used. This is error prone given it needs to happen in many places. It's debatable whether constant propagation is even correct in this case, as running the preloaded script on a restart isn't guaranteed to produce the same result. Hence, avoid the issue for now by just not relying on preloaded symbols when file cache is used. Fixes GH-21052 Closes GH-21281 --- NEWS | 2 ++ Zend/Optimizer/zend_optimizer.c | 6 ++++++ ext/opcache/tests/gh21052.phpt | 32 ++++++++++++++++++++++++++++++++ ext/opcache/tests/gh21052_a.inc | 13 +++++++++++++ ext/opcache/tests/gh21052_b.inc | 5 +++++ 5 files changed, 58 insertions(+) create mode 100644 ext/opcache/tests/gh21052.phpt create mode 100644 ext/opcache/tests/gh21052_a.inc create mode 100644 ext/opcache/tests/gh21052_b.inc diff --git a/NEWS b/NEWS index 28187bd8590e..b23bd68b8382 100644 --- a/NEWS +++ b/NEWS @@ -39,6 +39,8 @@ PHP NEWS (Petr Sumbera) . Fixed bug GH-21227 (Borked SCCP of array containing partial object). (ilutov) + . Fixed bug GH-21052 (Preloaded constant erroneously propagated to file-cached + script). (ilutov) - OpenSSL: . Fix a bunch of leaks and error propagation. (ndossche) diff --git a/Zend/Optimizer/zend_optimizer.c b/Zend/Optimizer/zend_optimizer.c index 25f16d252a83..9017572118e2 100644 --- a/Zend/Optimizer/zend_optimizer.c +++ b/Zend/Optimizer/zend_optimizer.c @@ -799,6 +799,9 @@ static bool zend_optimizer_ignore_class(zval *ce_zv, zend_string *filename) zend_class_entry *ce = Z_PTR_P(ce_zv); if (ce->ce_flags & ZEND_ACC_PRELOADED) { + if (CG(compiler_options) & ZEND_COMPILE_WITH_FILE_CACHE) { + return true; + } Bucket *ce_bucket = (Bucket*)((uintptr_t)ce_zv - XtOffsetOf(Bucket, val)); size_t offset = ce_bucket - EG(class_table)->arData; if (offset < EG(persistent_classes_count)) { @@ -817,6 +820,9 @@ static bool zend_optimizer_ignore_function(zval *fbc_zv, zend_string *filename) return false; } else if (fbc->type == ZEND_USER_FUNCTION) { if (fbc->op_array.fn_flags & ZEND_ACC_PRELOADED) { + if (CG(compiler_options) & ZEND_COMPILE_WITH_FILE_CACHE) { + return true; + } Bucket *fbc_bucket = (Bucket*)((uintptr_t)fbc_zv - XtOffsetOf(Bucket, val)); size_t offset = fbc_bucket - EG(function_table)->arData; if (offset < EG(persistent_functions_count)) { diff --git a/ext/opcache/tests/gh21052.phpt b/ext/opcache/tests/gh21052.phpt new file mode 100644 index 000000000000..d9d0430b9eef --- /dev/null +++ b/ext/opcache/tests/gh21052.phpt @@ -0,0 +1,32 @@ +--TEST-- +GH-21052: Preloaded constant erroneously propagated to file-cached script +--CREDITS-- +Grummfy +--EXTENSIONS-- +opcache +--INI-- +opcache.enable=1 +opcache.enable_cli=1 +opcache.file_cache="{TMP}" +opcache.preload={PWD}/gh21052_a.inc +--SKIPIF-- + +--FILE-- + +--EXPECT-- +array(1) { + [0]=> + string(3) "foo" +} +array(1) { + [0]=> + string(3) "foo" +} +array(1) { + [0]=> + string(3) "foo" +} diff --git a/ext/opcache/tests/gh21052_a.inc b/ext/opcache/tests/gh21052_a.inc new file mode 100644 index 000000000000..f9614369798b --- /dev/null +++ b/ext/opcache/tests/gh21052_a.inc @@ -0,0 +1,13 @@ + Date: Tue, 24 Feb 2026 11:54:25 -0500 Subject: [PATCH 2/3] Fix missed php_version changes --- main/php_version.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/main/php_version.h b/main/php_version.h index 859fde69b425..aae2ff323259 100644 --- a/main/php_version.h +++ b/main/php_version.h @@ -2,7 +2,7 @@ /* edit configure.ac to change version number */ #define PHP_MAJOR_VERSION 8 #define PHP_MINOR_VERSION 5 -#define PHP_RELEASE_VERSION 4 +#define PHP_RELEASE_VERSION 5 #define PHP_EXTRA_VERSION "-dev" #define PHP_VERSION "8.5.5-dev" -#define PHP_VERSION_ID 80504 +#define PHP_VERSION_ID 80505 From 6c45f7a000bc1748565fca72b1e527e45be574df Mon Sep 17 00:00:00 2001 From: David Carlier Date: Tue, 24 Feb 2026 20:58:01 +0000 Subject: [PATCH 3/3] ext/pcre: preg_match() fix memory leak with invalid regexes. close GH-21290 --- NEWS | 3 +++ ext/pcre/php_pcre.c | 3 ++- ext/pcre/tests/preg_match_frameless_leak.phpt | 26 +++++++++++++++++++ 3 files changed, 31 insertions(+), 1 deletion(-) create mode 100644 ext/pcre/tests/preg_match_frameless_leak.phpt diff --git a/NEWS b/NEWS index b23bd68b8382..159e337cde3f 100644 --- a/NEWS +++ b/NEWS @@ -55,6 +55,9 @@ PHP NEWS . Fixed pcntl_signal_dispatch() stale pointer and exception handling. (David Carlier) +- PCRE: + . Fixed preg_match memory leak with invalid regexes. (David Carlier) + - PDO_PGSQL: . Fixed bug GH-21055 (connection attribute status typo for GSS negotiation). (lsaos) diff --git a/ext/pcre/php_pcre.c b/ext/pcre/php_pcre.c index 5671957daac5..24931466199c 100644 --- a/ext/pcre/php_pcre.c +++ b/ext/pcre/php_pcre.c @@ -1489,7 +1489,8 @@ ZEND_FRAMELESS_FUNCTION(preg_match, 2) /* Compile regex or get it from cache. */ pcre_cache_entry *pce; if ((pce = pcre_get_compiled_regex_cache(regex)) == NULL) { - RETURN_FALSE; + RETVAL_FALSE; + goto flf_clean; } pce->refcount++; diff --git a/ext/pcre/tests/preg_match_frameless_leak.phpt b/ext/pcre/tests/preg_match_frameless_leak.phpt new file mode 100644 index 000000000000..52bbfeceee0d --- /dev/null +++ b/ext/pcre/tests/preg_match_frameless_leak.phpt @@ -0,0 +1,26 @@ +--TEST-- +Memory leak in preg_match() frameless function with invalid regex and object arguments +--FILE-- +val = $val; + } + public function __toString() { + return $this->val; + } +} + +$regex = new Str("invalid regex"); +$subject = new Str("some subject"); + +// Running in a loop to ensure leak detection if run with memory tools +for ($i = 0; $i < 100; $i++) { + @preg_match($regex, $subject); +} + +echo "Done"; +?> +--EXPECT-- +Done