summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNikita Popov <nikita.ppv@gmail.com>2020-11-05 11:58:31 +0100
committerNikita Popov <nikita.ppv@gmail.com>2020-11-05 16:35:08 +0100
commit6808968c896a18d2b9f309b2fe63d529058b78b4 (patch)
tree89ff62a43d911c81eeed8e79fe3bbc802d7d84a6
parent00e41a10b8b7c3e14f4aab680157489219ab4a86 (diff)
downloadphp-git-6808968c896a18d2b9f309b2fe63d529058b78b4.tar.gz
Backport preloading trait fixup fixes
This cherry-picks 33969c2252b2c33a72c9039072af8862fd347a5f and 2effbfd8713936742ef46e6e85ce193b320ac005 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.
-rw-r--r--ext/opcache/ZendAccelerator.c35
-rw-r--r--ext/opcache/tests/preload_trait_multiple_fixup.inc33
-rw-r--r--ext/opcache/tests/preload_trait_multiple_fixup.phpt20
3 files changed, 69 insertions, 19 deletions
diff --git a/ext/opcache/ZendAccelerator.c b/ext/opcache/ZendAccelerator.c
index 21dba385da..7cc301013b 100644
--- a/ext/opcache/ZendAccelerator.c
+++ b/ext/opcache/ZendAccelerator.c
@@ -4052,7 +4052,8 @@ static void preload_register_trait_methods(zend_class_entry *ce) {
zend_op_array *op_array;
ZEND_HASH_FOREACH_PTR(&ce->function_table, op_array) {
if (!(op_array->fn_flags & ZEND_ACC_TRAIT_CLONE)) {
- zend_shared_alloc_register_xlat_entry(op_array->opcodes, op_array);
+ ZEND_ASSERT(op_array->refcount && "Must have refcount pointer");
+ zend_shared_alloc_register_xlat_entry(op_array->refcount, op_array);
}
} ZEND_HASH_FOREACH_END();
}
@@ -4063,18 +4064,18 @@ static void preload_fix_trait_methods(zend_class_entry *ce)
ZEND_HASH_FOREACH_PTR(&ce->function_table, op_array) {
if (op_array->fn_flags & ZEND_ACC_TRAIT_CLONE) {
- zend_op_array *orig_op_array = zend_shared_alloc_get_xlat_entry(op_array->opcodes);
- if (orig_op_array) {
- zend_class_entry *scope = op_array->scope;
- uint32_t fn_flags = op_array->fn_flags;
- zend_function *prototype = op_array->prototype;
- HashTable *ht = op_array->static_variables;
- *op_array = *orig_op_array;
- op_array->scope = scope;
- op_array->fn_flags = fn_flags;
- op_array->prototype = prototype;
- op_array->static_variables = ht;
- }
+ zend_op_array *orig_op_array = zend_shared_alloc_get_xlat_entry(op_array->refcount);
+ ZEND_ASSERT(orig_op_array && "Must be in xlat table");
+
+ zend_class_entry *scope = op_array->scope;
+ uint32_t fn_flags = op_array->fn_flags;
+ zend_function *prototype = op_array->prototype;
+ HashTable *ht = op_array->static_variables;
+ *op_array = *orig_op_array;
+ op_array->scope = scope;
+ op_array->fn_flags = fn_flags;
+ op_array->prototype = prototype;
+ op_array->static_variables = ht;
}
} ZEND_HASH_FOREACH_END();
}
@@ -4105,16 +4106,12 @@ static int preload_optimize(zend_persistent_script *script)
}
ZEND_HASH_FOREACH_PTR(&script->script.class_table, ce) {
- if (ce->ce_flags & ZEND_ACC_IMPLEMENT_TRAITS) {
- preload_fix_trait_methods(ce);
- }
+ preload_fix_trait_methods(ce);
} ZEND_HASH_FOREACH_END();
ZEND_HASH_FOREACH_PTR(preload_scripts, script) {
ZEND_HASH_FOREACH_PTR(&script->script.class_table, ce) {
- if (ce->ce_flags & ZEND_ACC_IMPLEMENT_TRAITS) {
- preload_fix_trait_methods(ce);
- }
+ preload_fix_trait_methods(ce);
} ZEND_HASH_FOREACH_END();
} ZEND_HASH_FOREACH_END();
diff --git a/ext/opcache/tests/preload_trait_multiple_fixup.inc b/ext/opcache/tests/preload_trait_multiple_fixup.inc
new file mode 100644
index 0000000000..c6c2023725
--- /dev/null
+++ b/ext/opcache/tests/preload_trait_multiple_fixup.inc
@@ -0,0 +1,33 @@
+<?php
+
+trait T1 {
+ public function method() {
+ // Needs to be optimized somehow.
+ $str = "Foo";
+ echo "$str\n";
+ }
+}
+
+trait T2 {}
+
+class C1 {
+ use T1;
+}
+
+class C2 extends C1 {
+ use T2;
+}
+
+trait T3 {
+ public function method() {
+ // Prevent trivial inheritance.
+ static $x;
+ // Needs to be optimized somehow.
+ $str = "Foo";
+ echo "$str\n";
+ }
+}
+class C3 {
+ use T3;
+}
+class C4 extends C3 {}
diff --git a/ext/opcache/tests/preload_trait_multiple_fixup.phpt b/ext/opcache/tests/preload_trait_multiple_fixup.phpt
new file mode 100644
index 0000000000..dbee2595c2
--- /dev/null
+++ b/ext/opcache/tests/preload_trait_multiple_fixup.phpt
@@ -0,0 +1,20 @@
+--TEST--
+Op array fixed up multiple times during preloading
+--INI--
+opcache.enable=1
+opcache.enable_cli=1
+opcache.optimization_level=-1
+opcache.preload={PWD}/preload_trait_multiple_fixup.inc
+--SKIPIF--
+<?php
+require_once('skipif.inc');
+if (PHP_OS_FAMILY == 'Windows') die('skip Preloading is not supported on Windows');
+?>
+--FILE--
+<?php
+(new C2)->method();
+(new C4)->method();
+?>
+--EXPECT--
+Foo
+Foo