Skip to content

Commit 6808968

Browse files
committed
Backport preloading trait fixup fixes
This cherry-picks 33969c2 and 2effbfd from PHP-8.0. The issues these commits fix could also manifest in PHP 7.4, and a commenter on bug #80307 reports this this might indeed be happening.
1 parent 00e41a1 commit 6808968

File tree

3 files changed

+69
-19
lines changed

3 files changed

+69
-19
lines changed

ext/opcache/ZendAccelerator.c

Lines changed: 16 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -4052,7 +4052,8 @@ static void preload_register_trait_methods(zend_class_entry *ce) {
40524052
zend_op_array *op_array;
40534053
ZEND_HASH_FOREACH_PTR(&ce->function_table, op_array) {
40544054
if (!(op_array->fn_flags & ZEND_ACC_TRAIT_CLONE)) {
4055-
zend_shared_alloc_register_xlat_entry(op_array->opcodes, op_array);
4055+
ZEND_ASSERT(op_array->refcount && "Must have refcount pointer");
4056+
zend_shared_alloc_register_xlat_entry(op_array->refcount, op_array);
40564057
}
40574058
} ZEND_HASH_FOREACH_END();
40584059
}
@@ -4063,18 +4064,18 @@ static void preload_fix_trait_methods(zend_class_entry *ce)
40634064

40644065
ZEND_HASH_FOREACH_PTR(&ce->function_table, op_array) {
40654066
if (op_array->fn_flags & ZEND_ACC_TRAIT_CLONE) {
4066-
zend_op_array *orig_op_array = zend_shared_alloc_get_xlat_entry(op_array->opcodes);
4067-
if (orig_op_array) {
4068-
zend_class_entry *scope = op_array->scope;
4069-
uint32_t fn_flags = op_array->fn_flags;
4070-
zend_function *prototype = op_array->prototype;
4071-
HashTable *ht = op_array->static_variables;
4072-
*op_array = *orig_op_array;
4073-
op_array->scope = scope;
4074-
op_array->fn_flags = fn_flags;
4075-
op_array->prototype = prototype;
4076-
op_array->static_variables = ht;
4077-
}
4067+
zend_op_array *orig_op_array = zend_shared_alloc_get_xlat_entry(op_array->refcount);
4068+
ZEND_ASSERT(orig_op_array && "Must be in xlat table");
4069+
4070+
zend_class_entry *scope = op_array->scope;
4071+
uint32_t fn_flags = op_array->fn_flags;
4072+
zend_function *prototype = op_array->prototype;
4073+
HashTable *ht = op_array->static_variables;
4074+
*op_array = *orig_op_array;
4075+
op_array->scope = scope;
4076+
op_array->fn_flags = fn_flags;
4077+
op_array->prototype = prototype;
4078+
op_array->static_variables = ht;
40784079
}
40794080
} ZEND_HASH_FOREACH_END();
40804081
}
@@ -4105,16 +4106,12 @@ static int preload_optimize(zend_persistent_script *script)
41054106
}
41064107

41074108
ZEND_HASH_FOREACH_PTR(&script->script.class_table, ce) {
4108-
if (ce->ce_flags & ZEND_ACC_IMPLEMENT_TRAITS) {
4109-
preload_fix_trait_methods(ce);
4110-
}
4109+
preload_fix_trait_methods(ce);
41114110
} ZEND_HASH_FOREACH_END();
41124111

41134112
ZEND_HASH_FOREACH_PTR(preload_scripts, script) {
41144113
ZEND_HASH_FOREACH_PTR(&script->script.class_table, ce) {
4115-
if (ce->ce_flags & ZEND_ACC_IMPLEMENT_TRAITS) {
4116-
preload_fix_trait_methods(ce);
4117-
}
4114+
preload_fix_trait_methods(ce);
41184115
} ZEND_HASH_FOREACH_END();
41194116
} ZEND_HASH_FOREACH_END();
41204117

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
<?php
2+
3+
trait T1 {
4+
public function method() {
5+
// Needs to be optimized somehow.
6+
$str = "Foo";
7+
echo "$str\n";
8+
}
9+
}
10+
11+
trait T2 {}
12+
13+
class C1 {
14+
use T1;
15+
}
16+
17+
class C2 extends C1 {
18+
use T2;
19+
}
20+
21+
trait T3 {
22+
public function method() {
23+
// Prevent trivial inheritance.
24+
static $x;
25+
// Needs to be optimized somehow.
26+
$str = "Foo";
27+
echo "$str\n";
28+
}
29+
}
30+
class C3 {
31+
use T3;
32+
}
33+
class C4 extends C3 {}
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
--TEST--
2+
Op array fixed up multiple times during preloading
3+
--INI--
4+
opcache.enable=1
5+
opcache.enable_cli=1
6+
opcache.optimization_level=-1
7+
opcache.preload={PWD}/preload_trait_multiple_fixup.inc
8+
--SKIPIF--
9+
<?php
10+
require_once('skipif.inc');
11+
if (PHP_OS_FAMILY == 'Windows') die('skip Preloading is not supported on Windows');
12+
?>
13+
--FILE--
14+
<?php
15+
(new C2)->method();
16+
(new C4)->method();
17+
?>
18+
--EXPECT--
19+
Foo
20+
Foo

0 commit comments

Comments
 (0)