diff --git a/Zend/Optimizer/zend_optimizer.c b/Zend/Optimizer/zend_optimizer.c index 9f2e3115d3666..25f16d252a831 100644 --- a/Zend/Optimizer/zend_optimizer.c +++ b/Zend/Optimizer/zend_optimizer.c @@ -1579,7 +1579,7 @@ void zend_foreach_op_array(zend_script *script, zend_op_array_func_t func, void if (property->ce == ce && property->hooks) { for (uint32_t i = 0; i < ZEND_PROPERTY_HOOK_COUNT; i++) { zend_function *hook = hooks[i]; - if (hook && hook->common.scope == ce) { + if (hook && hook->common.scope == ce && !(hooks[i]->op_array.fn_flags & ZEND_ACC_TRAIT_CLONE)) { zend_foreach_op_array_helper(&hooks[i]->op_array, func, context); } } diff --git a/Zend/zend_inheritance.c b/Zend/zend_inheritance.c index b1ed8e4b61675..6f399fbfec5ab 100644 --- a/Zend/zend_inheritance.c +++ b/Zend/zend_inheritance.c @@ -2976,6 +2976,7 @@ static void zend_do_traits_property_binding(zend_class_entry *ce, zend_class_ent } } ce->ce_flags |= ZEND_ACC_USE_GUARDS; + ce->num_hooked_props++; } } ZEND_HASH_FOREACH_END(); } diff --git a/ext/opcache/ZendAccelerator.c b/ext/opcache/ZendAccelerator.c index 459449d85f23c..ec2948550e442 100644 --- a/ext/opcache/ZendAccelerator.c +++ b/ext/opcache/ZendAccelerator.c @@ -4202,12 +4202,52 @@ static void preload_remove_empty_includes(void) static void preload_register_trait_methods(zend_class_entry *ce) { zend_op_array *op_array; + zend_property_info *info; + ZEND_HASH_MAP_FOREACH_PTR(&ce->function_table, op_array) { if (!(op_array->fn_flags & ZEND_ACC_TRAIT_CLONE)) { ZEND_ASSERT(op_array->refcount && "Must have refcount pointer"); zend_shared_alloc_register_xlat_entry(op_array->refcount, op_array); } } ZEND_HASH_FOREACH_END(); + + if (ce->num_hooked_props > 0) { + ZEND_HASH_MAP_FOREACH_PTR(&ce->properties_info, info) { + if (info->hooks) { + for (uint32_t i = 0; i < ZEND_PROPERTY_HOOK_COUNT; i++) { + if (info->hooks[i]) { + op_array = &info->hooks[i]->op_array; + if (!(op_array->fn_flags & ZEND_ACC_TRAIT_CLONE)) { + ZEND_ASSERT(op_array->refcount && "Must have refcount pointer"); + zend_shared_alloc_register_xlat_entry(op_array->refcount, op_array); + } + } + } + } + } ZEND_HASH_FOREACH_END(); + } +} + +static void preload_fix_trait_op_array(zend_op_array *op_array) +{ + if (!(op_array->fn_flags & ZEND_ACC_TRAIT_CLONE)) { + return; + } + + 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_string *function_name = op_array->function_name; + 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->function_name = function_name; + op_array->scope = scope; + op_array->fn_flags = fn_flags; + op_array->prototype = prototype; + op_array->static_variables = ht; } static void preload_fix_trait_methods(zend_class_entry *ce) @@ -4215,23 +4255,22 @@ static void preload_fix_trait_methods(zend_class_entry *ce) zend_op_array *op_array; ZEND_HASH_MAP_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->refcount); - ZEND_ASSERT(orig_op_array && "Must be in xlat table"); - - zend_string *function_name = op_array->function_name; - 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->function_name = function_name; - op_array->scope = scope; - op_array->fn_flags = fn_flags; - op_array->prototype = prototype; - op_array->static_variables = ht; - } + preload_fix_trait_op_array(op_array); } ZEND_HASH_FOREACH_END(); + + if (ce->num_hooked_props > 0) { + zend_property_info *info; + ZEND_HASH_MAP_FOREACH_PTR(&ce->properties_info, info) { + if (info->hooks) { + for (uint32_t i = 0; i < ZEND_PROPERTY_HOOK_COUNT; i++) { + if (info->hooks[i]) { + op_array = &info->hooks[i]->op_array; + preload_fix_trait_op_array(op_array); + } + } + } + } ZEND_HASH_FOREACH_END(); + } } static void preload_optimize(zend_persistent_script *script) diff --git a/ext/opcache/tests/gh18534.phpt b/ext/opcache/tests/gh18534.phpt new file mode 100644 index 0000000000000..87181470793bd --- /dev/null +++ b/ext/opcache/tests/gh18534.phpt @@ -0,0 +1,21 @@ +--TEST-- +GH-18534 (FPM exit code 70 with enabled opcache and hooked properties in traits) +--EXTENSIONS-- +opcache +--SKIPIF-- + +--INI-- +opcache.enable=1 +opcache.enable_cli=1 +opcache.preload={PWD}/gh18534_preload.inc +--FILE-- +dummyProperty2); + +?> +--EXPECT-- +NULL diff --git a/ext/opcache/tests/gh18534_preload.inc b/ext/opcache/tests/gh18534_preload.inc new file mode 100644 index 0000000000000..22cee6165e533 --- /dev/null +++ b/ext/opcache/tests/gh18534_preload.inc @@ -0,0 +1,13 @@ + null; + } +} + +class DummyModel +{ + use DummyTrait; +}