From 3a5edcca4702dd1aa8e3141aaaa6764a43087fb5 Mon Sep 17 00:00:00 2001 From: Ilija Tovilo Date: Mon, 29 Jan 2024 17:26:07 +0100 Subject: [PATCH] Fix create_object checks Since PHP 8.3, object handlers may be changed by setting ce->default_object_handlers, rather than in ce->create_object. Some checks need to be extended to check for the default handlers. Closes GH-13272 --- Zend/Optimizer/escape_analysis.c | 26 ++++++++++++++++++++------ Zend/Optimizer/zend_inference.c | 11 +++++++++-- 2 files changed, 29 insertions(+), 8 deletions(-) diff --git a/Zend/Optimizer/escape_analysis.c b/Zend/Optimizer/escape_analysis.c index b7c0a5ec446..193479bae4b 100644 --- a/Zend/Optimizer/escape_analysis.c +++ b/Zend/Optimizer/escape_analysis.c @@ -164,10 +164,17 @@ static bool is_allocation_def(zend_op_array *op_array, zend_ssa *ssa, int def, i /* These flags will always cause an exception */ ZEND_ACC_IMPLICIT_ABSTRACT_CLASS | ZEND_ACC_EXPLICIT_ABSTRACT_CLASS | ZEND_ACC_INTERFACE | ZEND_ACC_TRAIT; - if (ce && !ce->parent && !ce->create_object && !ce->constructor && - !ce->destructor && !ce->__get && !ce->__set && - !(ce->ce_flags & forbidden_flags) && - (ce->ce_flags & ZEND_ACC_CONSTANTS_UPDATED)) { + if (ce + && !ce->parent + && !ce->create_object + && ce->default_object_handlers->get_constructor == zend_std_get_constructor + && ce->default_object_handlers->dtor_obj == zend_objects_destroy_object + && !ce->constructor + && !ce->destructor + && !ce->__get + && !ce->__set + && !(ce->ce_flags & forbidden_flags) + && (ce->ce_flags & ZEND_ACC_CONSTANTS_UPDATED)) { return 1; } break; @@ -227,8 +234,15 @@ static bool is_local_def(zend_op_array *op_array, zend_ssa *ssa, int def, int va /* objects with destructors should escape */ zend_class_entry *ce = zend_optimizer_get_class_entry_from_op1( script, op_array, opline); - if (ce && !ce->create_object && !ce->constructor && - !ce->destructor && !ce->__get && !ce->__set && !ce->parent) { + if (ce + && !ce->create_object + && ce->default_object_handlers->get_constructor == zend_std_get_constructor + && ce->default_object_handlers->dtor_obj == zend_objects_destroy_object + && !ce->constructor + && !ce->destructor + && !ce->__get + && !ce->__set + && !ce->parent) { return 1; } break; diff --git a/Zend/Optimizer/zend_inference.c b/Zend/Optimizer/zend_inference.c index 759284f1045..34d31a38c40 100644 --- a/Zend/Optimizer/zend_inference.c +++ b/Zend/Optimizer/zend_inference.c @@ -3776,6 +3776,7 @@ static zend_always_inline zend_result _zend_update_type_info( /* Unset properties will resort back to __get/__set */ if (ce && !ce->create_object + && ce->default_object_handlers->read_property == zend_std_read_property && !ce->__get && !result_may_be_separated(ssa, ssa_op)) { tmp &= ~MAY_BE_RC1; @@ -5069,8 +5070,14 @@ ZEND_API bool zend_may_throw_ex(const zend_op *opline, const zend_ssa_op *ssa_op const zend_ssa_var_info *var_info = ssa->var_info + ssa_op->op1_use; const zend_class_entry *ce = var_info->ce; - if (var_info->is_instanceof || - !ce || ce->create_object || ce->__get || ce->__set || ce->parent) { + if (var_info->is_instanceof + || !ce + || ce->create_object + || ce->default_object_handlers->write_property != zend_std_write_property + || ce->default_object_handlers->get_property_ptr_ptr != zend_std_get_property_ptr_ptr + || ce->__get + || ce->__set + || ce->parent) { return 1; }