Skip to content

Commit 2e006f8

Browse files
committed
Fix preloading FCC const exprs
Preloading will try to evaluate class constants during compilation, but evaluated FCCs are objects, which can not be persisted. Apply the same fix as for enums: Fail evaluation when compiling. Preloading will also reset CG(map_ptr_last) after compilation, which results in collisions if map ptrs were allocated during compilation. Move the ZEND_MAP_PTR_NEW() to the persist phase, as a shared map ptr is not necessary before that.
1 parent 3154731 commit 2e006f8

6 files changed

Lines changed: 66 additions & 3 deletions

File tree

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
<?php
2+
3+
#[Attribute]
4+
class A {
5+
function __construct(public mixed $fn) {}
6+
}
7+
8+
#[A(strlen(...))]
9+
class C {
10+
const CC = strlen(...);
11+
12+
#[A(strlen(...))]
13+
function f($arg = strlen(...)) {
14+
return $arg;
15+
}
16+
}
17+
18+
const CC = strlen(...);
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
--TEST--
2+
GH-22782: FCC preloading
3+
--EXTENSIONS--
4+
opcache
5+
--INI--
6+
opcache.enable=1
7+
opcache.enable_cli=1
8+
opcache.optimization_level=-1
9+
opcache.preload={PWD}/gh22782.inc
10+
--SKIPIF--
11+
<?php
12+
if (PHP_OS_FAMILY == 'Windows') die('skip Preloading is not supported on Windows');
13+
?>
14+
--FILE--
15+
<?php
16+
17+
echo "# Class const\n";
18+
var_dump((C::CC)('hello'));
19+
echo "# Class attr\n";
20+
var_dump((new ReflectionClass(C::class)->getAttributes(A::class)[0]->newInstance()->fn)('hello'));
21+
echo "# Method attr\n";
22+
var_dump((new ReflectionMethod(C::class, 'f')->getAttributes(A::class)[0]->newInstance()->fn)('hello'));
23+
echo "# Method default value\n";
24+
var_dump((new C()->f())('hello'));
25+
26+
?>
27+
--EXPECT--
28+
# Class const
29+
int(5)
30+
# Class attr
31+
int(5)
32+
# Method attr
33+
int(5)
34+
# Method default value
35+
int(5)

Zend/zend_ast.c

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1054,6 +1054,12 @@ ZEND_API zend_result ZEND_FASTCALL zend_ast_evaluate_inner(
10541054
case ZEND_AST_CALL:
10551055
case ZEND_AST_STATIC_CALL:
10561056
{
1057+
// Preloading will attempt to resolve constants but objects can't be stored in shm
1058+
// Aborting here to store the const AST instead
1059+
if (CG(in_compilation)) {
1060+
return FAILURE;
1061+
}
1062+
10571063
zend_function *fptr;
10581064
zend_class_entry *called_scope = NULL;
10591065
switch (ast->kind) {

Zend/zend_compile.c

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11513,7 +11513,6 @@ static void zend_compile_const_expr_fcc(zend_ast **ast_ptr)
1151311513
if ((*args_ast)->kind != ZEND_AST_CALLABLE_CONVERT) {
1151411514
zend_error_noreturn(E_COMPILE_ERROR, "Constant expression contains invalid operations");
1151511515
}
11516-
ZEND_MAP_PTR_NEW(((zend_ast_fcc *)*args_ast)->fptr);
1151711516

1151811517
switch ((*ast_ptr)->kind) {
1151911518
case ZEND_AST_CALL: {

ext/opcache/zend_file_cache.c

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1303,7 +1303,9 @@ static void zend_file_cache_unserialize_ast(zend_ast *ast,
13031303
zend_ast_get_op_array(ast)->op_array = Z_PTR(z);
13041304
} else if (ast->kind == ZEND_AST_CALLABLE_CONVERT) {
13051305
zend_ast_fcc *fcc = (zend_ast_fcc*)ast;
1306-
ZEND_MAP_PTR_NEW(fcc->fptr);
1306+
if (!script->corrupted) {
1307+
ZEND_MAP_PTR_NEW(fcc->fptr);
1308+
}
13071309
} else if (zend_ast_is_decl(ast)) {
13081310
/* Not implemented. */
13091311
ZEND_UNREACHABLE();
@@ -2109,7 +2111,7 @@ void zend_file_cache_invalidate(zend_string *full_path)
21092111
if (ZCG(accel_directives).file_cache_read_only) {
21102112
return;
21112113
}
2112-
2114+
21132115
char *filename;
21142116

21152117
filename = zend_file_cache_get_bin_file_path(full_path);

ext/opcache/zend_persist.c

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -197,6 +197,9 @@ static zend_ast *zend_persist_ast(zend_ast *ast)
197197
node = (zend_ast *) copy;
198198
} else if (ast->kind == ZEND_AST_CALLABLE_CONVERT) {
199199
zend_ast_fcc *copy = zend_shared_memdup(ast, sizeof(zend_ast_fcc));
200+
if (!ZCG(current_persistent_script)->corrupted) {
201+
ZEND_MAP_PTR_NEW(copy->fptr);
202+
}
200203
node = (zend_ast *) copy;
201204
} else if (zend_ast_is_decl(ast)) {
202205
/* Not implemented. */

0 commit comments

Comments
 (0)