Skip to content

Commit ec5a1e0

Browse files
committed
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
1 parent e792511 commit ec5a1e0

File tree

5 files changed

+58
-0
lines changed

5 files changed

+58
-0
lines changed

NEWS

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,8 @@ PHP NEWS
3939
(Petr Sumbera)
4040
. Fixed bug GH-21227 (Borked SCCP of array containing partial object).
4141
(ilutov)
42+
. Fixed bug GH-21052 (Preloaded constant erroneously propagated to file-cached
43+
script). (ilutov)
4244

4345
- OpenSSL:
4446
. Fix a bunch of leaks and error propagation. (ndossche)

Zend/Optimizer/zend_optimizer.c

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -799,6 +799,9 @@ static bool zend_optimizer_ignore_class(zval *ce_zv, zend_string *filename)
799799
zend_class_entry *ce = Z_PTR_P(ce_zv);
800800

801801
if (ce->ce_flags & ZEND_ACC_PRELOADED) {
802+
if (CG(compiler_options) & ZEND_COMPILE_WITH_FILE_CACHE) {
803+
return true;
804+
}
802805
Bucket *ce_bucket = (Bucket*)((uintptr_t)ce_zv - XtOffsetOf(Bucket, val));
803806
size_t offset = ce_bucket - EG(class_table)->arData;
804807
if (offset < EG(persistent_classes_count)) {
@@ -817,6 +820,9 @@ static bool zend_optimizer_ignore_function(zval *fbc_zv, zend_string *filename)
817820
return false;
818821
} else if (fbc->type == ZEND_USER_FUNCTION) {
819822
if (fbc->op_array.fn_flags & ZEND_ACC_PRELOADED) {
823+
if (CG(compiler_options) & ZEND_COMPILE_WITH_FILE_CACHE) {
824+
return true;
825+
}
820826
Bucket *fbc_bucket = (Bucket*)((uintptr_t)fbc_zv - XtOffsetOf(Bucket, val));
821827
size_t offset = fbc_bucket - EG(function_table)->arData;
822828
if (offset < EG(persistent_functions_count)) {

ext/opcache/tests/gh21052.phpt

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
--TEST--
2+
GH-21052: Preloaded constant erroneously propagated to file-cached script
3+
--CREDITS--
4+
Grummfy
5+
--EXTENSIONS--
6+
opcache
7+
--INI--
8+
opcache.enable=1
9+
opcache.enable_cli=1
10+
opcache.file_cache="{TMP}"
11+
opcache.preload={PWD}/gh21052_a.inc
12+
--SKIPIF--
13+
<?php
14+
if (PHP_OS_FAMILY == 'Windows') die('skip Preloading is not supported on Windows');
15+
?>
16+
--FILE--
17+
<?php
18+
require __DIR__ . '/gh21052_b.inc';
19+
?>
20+
--EXPECT--
21+
array(1) {
22+
[0]=>
23+
string(3) "foo"
24+
}
25+
array(1) {
26+
[0]=>
27+
string(3) "foo"
28+
}
29+
array(1) {
30+
[0]=>
31+
string(3) "foo"
32+
}

ext/opcache/tests/gh21052_a.inc

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
<?php
2+
3+
class A {
4+
const C = ['foo'];
5+
6+
public static function test() {
7+
return ['foo'];
8+
}
9+
}
10+
11+
function test() {
12+
return ['foo'];
13+
}

ext/opcache/tests/gh21052_b.inc

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
<?php
2+
3+
var_dump(A::C);
4+
var_dump(A::test());
5+
var_dump(test());

0 commit comments

Comments
 (0)