[php-src] master: Merge branch 'PHP-8.5'

Arnaud Le Blanc <[email protected]> Wed, 22 Jul 2026 07:49:18 +0000
Newsgroups gmane.comp.php.cvs.general
Message-ID <[email protected]>
Author: Arnaud Le Blanc (arnaud-lb)
Date: 2026-07-22T09:46:48+02:00

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

Merge branch 'PHP-8.5'

* PHP-8.5:
  Fix const expr support in preloading (#22783)

Changed paths:
  A  Zend/tests/first_class_callable/constexpr/gh22782.inc
  A  Zend/tests/first_class_callable/constexpr/gh22782.phpt
  M  Zend/zend_ast.c
  M  Zend/zend_compile.c
  M  ext/opcache/zend_file_cache.c
  M  ext/opcache/zend_persist.c


Diff:

diff --git a/Zend/tests/first_class_callable/constexpr/gh22782.inc b/Zend/tests/first_class_callable/constexpr/gh22782.inc
new file mode 100644
index 000000000000..d67ba4eab14e
--- /dev/null
+++ b/Zend/tests/first_class_callable/constexpr/gh22782.inc
@@ -0,0 +1,18 @@
+<?php
+
+#[Attribute]
+class A {
+    function __construct(public mixed $fn) {}
+}
+
+#[A(strlen(...))]
+class C {
+    const CC = strlen(...);
+
+    #[A(strlen(...))]
+    function f($arg = strlen(...)) {
+        return $arg;
+    }
+}
+
+const CC = strlen(...);
diff --git a/Zend/tests/first_class_callable/constexpr/gh22782.phpt b/Zend/tests/first_class_callable/constexpr/gh22782.phpt
new file mode 100644
index 000000000000..b30820be9805
--- /dev/null
+++ b/Zend/tests/first_class_callable/constexpr/gh22782.phpt
@@ -0,0 +1,35 @@
+--TEST--
+GH-22782: FCC preloading
+--EXTENSIONS--
+opcache
+--INI--
+opcache.enable=1
+opcache.enable_cli=1
+opcache.optimization_level=-1
+opcache.preload={PWD}/gh22782.inc
+--SKIPIF--
+<?php
+if (PHP_OS_FAMILY == 'Windows') die('skip Preloading is not supported on Windows');
+?>
+--FILE--
+<?php
+
+echo "# Class const\n";
+var_dump((C::CC)('hello'));
+echo "# Class attr\n";
+var_dump((new ReflectionClass(C::class)->getAttributes(A::class)[0]->newInstance()->fn)('hello'));
+echo "# Method attr\n";
+var_dump((new ReflectionMethod(C::class, 'f')->getAttributes(A::class)[0]->newInstance()->fn)('hello'));
+echo "# Method default value\n";
+var_dump((new C()->f())('hello'));
+
+?>
+--EXPECT--
+# Class const
+int(5)
+# Class attr
+int(5)
+# Method attr
+int(5)
+# Method default value
+int(5)
diff --git a/Zend/zend_ast.c b/Zend/zend_ast.c
index adcb62a51d1f..1b293c832c91 100644
--- a/Zend/zend_ast.c
+++ b/Zend/zend_ast.c
@@ -1139,6 +1139,12 @@ static zend_result ZEND_FASTCALL zend_ast_evaluate_inner(
 		case ZEND_AST_CALL:
 		case ZEND_AST_STATIC_CALL:
 		{
+			// Preloading will attempt to resolve constants but objects can't be stored in shm
+			// Aborting here to store the const AST instead
+			if (CG(in_compilation)) {
+				return FAILURE;
+			}
+
 			zend_function *fptr;
 			zend_class_entry *called_scope = NULL;
 
diff --git a/Zend/zend_compile.c b/Zend/zend_compile.c
index bb24d73fb240..6a677e71a6b6 100644
--- a/Zend/zend_compile.c
+++ b/Zend/zend_compile.c
@@ -12037,8 +12037,6 @@ static void zend_compile_const_expr_fcc(zend_ast **ast_ptr)
 		zend_error_noreturn(E_COMPILE_ERROR, "Constant expression contains invalid operations");
 	}
 
-	ZEND_MAP_PTR_NEW(((zend_ast_fcc *)*args_ast)->fptr);
-
 	switch ((*ast_ptr)->kind) {
 		case ZEND_AST_CALL: {
 			zend_ast *name_ast = (*ast_ptr)->child[0];
diff --git a/ext/opcache/zend_file_cache.c b/ext/opcache/zend_file_cache.c
index af59b9b2c34a..265d5de41476 100644
--- a/ext/opcache/zend_file_cache.c
+++ b/ext/opcache/zend_file_cache.c
@@ -1308,7 +1308,9 @@ static void zend_file_cache_unserialize_ast(zend_ast                *ast,
 		zend_ast_get_op_array(ast)->op_array = Z_PTR(z);
 	} else if (ast->kind == ZEND_AST_CALLABLE_CONVERT) {
 		zend_ast_fcc *fcc = (zend_ast_fcc*)ast;
-		ZEND_MAP_PTR_NEW(fcc->fptr);
+		if (!script->corrupted) {
+			ZEND_MAP_PTR_NEW(fcc->fptr);
+		}
 		if (!IS_UNSERIALIZED(fcc->args)) {
 			UNSERIALIZE_PTR(fcc->args);
 			zend_file_cache_unserialize_ast(fcc->args, script, buf);
diff --git a/ext/opcache/zend_persist.c b/ext/opcache/zend_persist.c
index c06452e6acf2..d3e719dbed70 100644
--- a/ext/opcache/zend_persist.c
+++ b/ext/opcache/zend_persist.c
@@ -195,6 +195,9 @@ static zend_ast *zend_persist_ast(zend_ast *ast)
 		node = (zend_ast *) copy;
 	} else if (ast->kind == ZEND_AST_CALLABLE_CONVERT) {
 		zend_ast_fcc *copy = zend_shared_memdup(ast, sizeof(zend_ast_fcc));
+		if (!ZCG(current_persistent_script)->corrupted) {
+			ZEND_MAP_PTR_NEW(copy->fptr);
+		}
 		copy->args = zend_persist_ast(copy->args);
 		node = (zend_ast *) copy;
 	} else if (zend_ast_is_decl(ast)) {