diff --git a/Zend/tests/readonly_props/cpp_reassign_basic.phpt b/Zend/tests/readonly_props/cpp_reassign_basic.phpt new file mode 100644 index 0000000000000..3725baec13b0e --- /dev/null +++ b/Zend/tests/readonly_props/cpp_reassign_basic.phpt @@ -0,0 +1,28 @@ +--TEST-- +Promoted readonly property reassignment in constructor - basic +--FILE-- +x = abs($x); + $this->y = abs($y); + } +} + +$point = new Point(); +var_dump($point->x, $point->y); + +$point2 = new Point(-5.0, -3.0); +var_dump($point2->x, $point2->y); + +?> +--EXPECT-- +float(0) +float(0) +float(5) +float(3) diff --git a/Zend/tests/readonly_props/cpp_reassign_child_class.phpt b/Zend/tests/readonly_props/cpp_reassign_child_class.phpt new file mode 100644 index 0000000000000..b7215c05d0788 --- /dev/null +++ b/Zend/tests/readonly_props/cpp_reassign_child_class.phpt @@ -0,0 +1,93 @@ +--TEST-- +Promoted readonly property reassignment in constructor - child cannot reassign parent's property +--FILE-- +prop = 'child override'; + } catch (Error $e) { + echo $e->getMessage(), "\n"; + } + } +} + +$parent = new Parent1(); +var_dump($parent->prop); + +$child = new Child1(); +var_dump($child->prop); + +// Case 2: Parent USES reassignment, child cannot +class Parent2 { + public function __construct( + public readonly string $prop = 'parent default', + ) { + $this->prop = 'parent set'; // Uses the one reassignment + } +} + +class Child2 extends Parent2 { + public function __construct() { + parent::__construct(); + // Child cannot reassign - parent already used the one reassignment + try { + $this->prop = 'child override'; + } catch (Error $e) { + echo $e->getMessage(), "\n"; + } + } +} + +$child2 = new Child2(); +var_dump($child2->prop); + +// Case 3: Child with its own promoted property +class Parent3 { + public function __construct( + public readonly string $parentProp = 'parent default', + ) { + // Parent doesn't reassign + } +} + +class Child3 extends Parent3 { + public function __construct( + public readonly string $childProp = 'child default', + ) { + parent::__construct(); + // Child cannot reassign parent's property, but can reassign its own + try { + $this->parentProp = 'child set parent'; + } catch (Error $e) { + echo $e->getMessage(), "\n"; + } + $this->childProp = 'child set own'; + } +} + +$child3 = new Child3(); +var_dump($child3->parentProp, $child3->childProp); + +?> +--EXPECT-- +string(14) "parent default" +Cannot modify readonly property Parent1::$prop +string(14) "parent default" +Cannot modify readonly property Parent2::$prop +string(10) "parent set" +Cannot modify readonly property Parent3::$parentProp +string(14) "parent default" +string(13) "child set own" diff --git a/Zend/tests/readonly_props/cpp_reassign_child_preempt_parent.phpt b/Zend/tests/readonly_props/cpp_reassign_child_preempt_parent.phpt new file mode 100644 index 0000000000000..0eb0f4ff95bcc --- /dev/null +++ b/Zend/tests/readonly_props/cpp_reassign_child_preempt_parent.phpt @@ -0,0 +1,60 @@ +--TEST-- +Promoted readonly property reassignment in constructor - child preempt then parent ctor throws +--FILE-- +prop = 'parent set'; + } catch (Error) { + // readonly property set by child class + } + } +} + +class ChildNoCPP extends ParentNoCPP { + public function __construct() { + $this->prop = 'child set'; + parent::__construct(); + } +} + +class ParentCPP { + public function __construct( + public readonly string $prop = 'parent default', + ) { + try { + $this->prop = 'parent set'; + } catch (Error) { + // readonly property set by child class + } + } +} + +class ChildCPP extends ParentCPP { + public function __construct() { + $this->prop = 'child set'; + try { + parent::__construct(); + } catch (Error $e) { + echo $e->getMessage(), "\n"; + } + } +} + +$c = new ChildNoCPP(); +var_dump($c->prop); + +$c = new ChildCPP(); +var_dump($c->prop); + +?> +--EXPECT-- +string(9) "child set" +Cannot modify readonly property ParentCPP::$prop +string(9) "child set" diff --git a/Zend/tests/readonly_props/cpp_reassign_conditional.phpt b/Zend/tests/readonly_props/cpp_reassign_conditional.phpt new file mode 100644 index 0000000000000..6c751d72af7d4 --- /dev/null +++ b/Zend/tests/readonly_props/cpp_reassign_conditional.phpt @@ -0,0 +1,23 @@ +--TEST-- +Promoted readonly property reassignment in constructor - conditional initialization +--FILE-- +cacheDir ??= sys_get_temp_dir() . '/app_cache'; + } +} + +$config1 = new Config(); +var_dump(str_contains($config1->cacheDir, 'app_cache')); + +$config2 = new Config('/custom/cache'); +var_dump($config2->cacheDir); + +?> +--EXPECT-- +bool(true) +string(13) "/custom/cache" diff --git a/Zend/tests/readonly_props/cpp_reassign_different_object.phpt b/Zend/tests/readonly_props/cpp_reassign_different_object.phpt new file mode 100644 index 0000000000000..da81c17be8ae5 --- /dev/null +++ b/Zend/tests/readonly_props/cpp_reassign_different_object.phpt @@ -0,0 +1,66 @@ +--TEST-- +Promoted readonly property reassignment in constructor - different object fails +--FILE-- +x = abs($x); + } + + public static function createFrom(Point $other): Point { + $new = new self(); + // Cannot modify another object's readonly property + try { + $other->x = 999.0; + } catch (Error $e) { + echo $e->getMessage(), "\n"; + } + return $new; + } +} + +$p1 = new Point(-5.0); +var_dump($p1->x); + +$p2 = Point::createFrom($p1); +var_dump($p1->x); // Unchanged + +// Also test: constructor cannot modify another instance of the same class +class Counter { + private static ?Counter $last = null; + + public function __construct( + public readonly int $value = 0, + ) { + $this->value = $value + 1; // Allowed: own property + + // Cannot modify previous instance + if (self::$last !== null) { + try { + self::$last->value = 999; + } catch (Error $e) { + echo $e->getMessage(), "\n"; + } + } + self::$last = $this; + } +} + +$c1 = new Counter(10); +var_dump($c1->value); + +$c2 = new Counter(20); +var_dump($c1->value, $c2->value); // $c1 unchanged + +?> +--EXPECT-- +float(5) +Cannot modify readonly property Point::$x +float(5) +int(11) +Cannot modify readonly property Counter::$value +int(11) +int(21) diff --git a/Zend/tests/readonly_props/cpp_reassign_direct_ctor_call.phpt b/Zend/tests/readonly_props/cpp_reassign_direct_ctor_call.phpt new file mode 100644 index 0000000000000..dd936ff41ad16 --- /dev/null +++ b/Zend/tests/readonly_props/cpp_reassign_direct_ctor_call.phpt @@ -0,0 +1,51 @@ +--TEST-- +Promoted readonly properties cannot be reassigned when __construct() is called directly +--FILE-- +value . "\n"; + +// Direct call to __construct() should NOT allow reassignment +try { + $obj->__construct('modified'); + echo "After direct __construct: " . $obj->value . "\n"; +} catch (Error $e) { + echo "Error: " . $e->getMessage() . "\n"; +} + +// Also test with a class that uses reassignment +class Bar { + public function __construct( + public readonly string $value = 'default', + ) { + $this->value = strtoupper($this->value); + } +} + +$bar = new Bar('hello'); +echo "Bar initial value: " . $bar->value . "\n"; + +// Direct call should fail during the CPP assignment (property not UNINIT) +// Note: The error happens inside the constructor because CPP assignment happens first +try { + $bar->__construct('world'); + echo "After direct __construct: " . $bar->value . "\n"; +} catch (Error $e) { + echo "Error: " . $e->getMessage() . "\n"; +} + +?> +--EXPECT-- +Initial value: initial +Error: Cannot modify readonly property Foo::$value +Bar initial value: HELLO +Error: Cannot modify readonly property Bar::$value diff --git a/Zend/tests/readonly_props/cpp_reassign_indirect_allowed.phpt b/Zend/tests/readonly_props/cpp_reassign_indirect_allowed.phpt new file mode 100644 index 0000000000000..d126da231030c --- /dev/null +++ b/Zend/tests/readonly_props/cpp_reassign_indirect_allowed.phpt @@ -0,0 +1,63 @@ +--TEST-- +Promoted readonly property reassignment in constructor - indirect reassignment allowed +--FILE-- +initProp(); + } + + private function initProp(): void { + $this->prop = 'from method'; + } +} + +$cm = new CalledMethod(); +var_dump($cm->prop); + +// Reassignment IS allowed in closures called by the constructor +class ClosureInConstructor { + public function __construct( + public readonly string $prop = 'default', + ) { + $fn = function() { + $this->prop = 'from closure'; + }; + $fn(); + } +} + +$cc = new ClosureInConstructor(); +var_dump($cc->prop); + +// But second reassignment still fails +class MultipleReassign { + public function __construct( + public readonly string $prop = 'default', + ) { + $this->initProp(); + try { + $this->initProp(); // Second call - should fail + } catch (Error $e) { + echo $e->getMessage(), "\n"; + } + } + + private function initProp(): void { + $this->prop = 'from method'; + } +} + +$mr = new MultipleReassign(); +var_dump($mr->prop); + +?> +--EXPECT-- +string(11) "from method" +string(12) "from closure" +Cannot modify readonly property MultipleReassign::$prop +string(11) "from method" diff --git a/Zend/tests/readonly_props/cpp_reassign_indirect_ops.phpt b/Zend/tests/readonly_props/cpp_reassign_indirect_ops.phpt new file mode 100644 index 0000000000000..da51ad6be4661 --- /dev/null +++ b/Zend/tests/readonly_props/cpp_reassign_indirect_ops.phpt @@ -0,0 +1,68 @@ +--TEST-- +Promoted readonly property reassignment in constructor - indirect operations (++, --, +=) +--FILE-- +count++; + } +} + +$c = new Counter(5); +var_dump($c->count); + +// Multiple operations count as reassignments - second fails +class MultiOp { + public function __construct( + public readonly int $value = 10, + ) { + $this->value += 5; // First modification - allowed + try { + $this->value++; // Second modification - should fail + } catch (Error $e) { + echo $e->getMessage(), "\n"; + } + } +} + +$m = new MultiOp(); +var_dump($m->value); + +// Decrement works too +class Decrement { + public function __construct( + public readonly int $value = 100, + ) { + $this->value--; + } +} + +$d = new Decrement(); +var_dump($d->value); + +// Assignment operators work +class AssignOps { + public function __construct( + public readonly string $text = 'hello', + ) { + $this->text .= ' world'; + } +} + +$a = new AssignOps(); +var_dump($a->text); + +?> +--EXPECT-- +int(6) +Cannot modify readonly property MultiOp::$value +int(15) +int(99) +string(11) "hello world" diff --git a/Zend/tests/readonly_props/cpp_reassign_multiple_fail.phpt b/Zend/tests/readonly_props/cpp_reassign_multiple_fail.phpt new file mode 100644 index 0000000000000..f66ef39aebb63 --- /dev/null +++ b/Zend/tests/readonly_props/cpp_reassign_multiple_fail.phpt @@ -0,0 +1,25 @@ +--TEST-- +Promoted readonly property reassignment in constructor - multiple reassignments fail +--FILE-- +value = 'first'; // OK - first reassignment + try { + $this->value = 'second'; // Error - second reassignment + } catch (Error $e) { + echo $e->getMessage(), "\n"; + } + } +} + +$ex = new Example(); +var_dump($ex->value); + +?> +--EXPECT-- +Cannot modify readonly property Example::$value +string(5) "first" diff --git a/Zend/tests/readonly_props/cpp_reassign_nonpromoted.phpt b/Zend/tests/readonly_props/cpp_reassign_nonpromoted.phpt new file mode 100644 index 0000000000000..0b0c0f311e8c8 --- /dev/null +++ b/Zend/tests/readonly_props/cpp_reassign_nonpromoted.phpt @@ -0,0 +1,49 @@ +--TEST-- +Promoted readonly property reassignment in constructor - non-promoted properties unchanged +--FILE-- +prop = 'first'; + try { + $this->prop = 'second'; // Should fail - not a promoted property + } catch (Error $e) { + echo $e->getMessage(), "\n"; + } + } +} + +$np = new NonPromoted(); +var_dump($np->prop); + +// Test mixed: promoted and non-promoted in same class +class MixedProps { + public readonly string $nonPromoted; + + public function __construct( + public readonly string $promoted = 'default', + ) { + $this->nonPromoted = 'first'; + $this->promoted = 'reassigned'; // Allowed (promoted, first reassignment) + try { + $this->nonPromoted = 'second'; // Should fail (non-promoted) + } catch (Error $e) { + echo $e->getMessage(), "\n"; + } + } +} + +$m = new MixedProps(); +var_dump($m->promoted, $m->nonPromoted); + +?> +--EXPECT-- +Cannot modify readonly property NonPromoted::$prop +string(5) "first" +Cannot modify readonly property MixedProps::$nonPromoted +string(10) "reassigned" +string(5) "first" diff --git a/Zend/tests/readonly_props/cpp_reassign_outside_ctor.phpt b/Zend/tests/readonly_props/cpp_reassign_outside_ctor.phpt new file mode 100644 index 0000000000000..eb503f1db18e8 --- /dev/null +++ b/Zend/tests/readonly_props/cpp_reassign_outside_ctor.phpt @@ -0,0 +1,39 @@ +--TEST-- +Promoted readonly property reassignment in constructor - outside constructor fails +--FILE-- +x = abs($x); + } + + public function tryModify(): void { + $this->x = 999.0; + } +} + +$point = new Point(-5.0); +var_dump($point->x); + +// Cannot reassign from outside constructor +try { + $point->x = 100.0; +} catch (Error $e) { + echo $e->getMessage(), "\n"; +} + +// Cannot reassign from a method +try { + $point->tryModify(); +} catch (Error $e) { + echo $e->getMessage(), "\n"; +} + +?> +--EXPECT-- +float(5) +Cannot modify readonly property Point::$x +Cannot modify readonly property Point::$x diff --git a/Zend/tests/readonly_props/cpp_reassign_reflection.phpt b/Zend/tests/readonly_props/cpp_reassign_reflection.phpt new file mode 100644 index 0000000000000..e94e429a9aded --- /dev/null +++ b/Zend/tests/readonly_props/cpp_reassign_reflection.phpt @@ -0,0 +1,81 @@ +--TEST-- +Promoted readonly property reassignment works when object created via reflection +--FILE-- +bar = 'overwritten in constructor'; + } +} + +// Test 1: Object created via reflection without constructor, then __construct() called +echo "Test 1: Reflection newInstanceWithoutConstructor + explicit __construct()\n"; +$ref = new ReflectionClass(Foo::class); +$obj = $ref->newInstanceWithoutConstructor(); + +// Property should be uninitialized at this point +try { + echo $obj->bar; + echo "ERROR: Should have thrown for uninitialized property\n"; +} catch (Error $e) { + echo "OK: " . $e->getMessage() . "\n"; +} + +// Now call constructor - reassignment should work +$obj->__construct('explicit call'); +echo "After __construct: " . $obj->bar . "\n"; + +// Second __construct() call should fail +echo "\nTest 2: Second __construct() call should fail\n"; +try { + $obj->__construct('second call'); + echo "ERROR: Second __construct() should have failed\n"; +} catch (Error $e) { + echo "OK: " . $e->getMessage() . "\n"; +} + +// Test 3: Normal new still works +echo "\nTest 3: Normal 'new' still works\n"; +$obj2 = new Foo('via new'); +echo "After new: " . $obj2->bar . "\n"; + +// Second call should fail +try { + $obj2->__construct('second call'); + echo "ERROR: Should have failed\n"; +} catch (Error $e) { + echo "OK: " . $e->getMessage() . "\n"; +} + +// Test 4: Reflection newInstanceArgs (calls constructor) +echo "\nTest 4: Reflection newInstanceArgs\n"; +$obj3 = $ref->newInstanceArgs(['via newInstanceArgs']); +echo "After newInstanceArgs: " . $obj3->bar . "\n"; + +// Second call should fail +try { + $obj3->__construct('second call'); + echo "ERROR: Should have failed\n"; +} catch (Error $e) { + echo "OK: " . $e->getMessage() . "\n"; +} + +?> +--EXPECT-- +Test 1: Reflection newInstanceWithoutConstructor + explicit __construct() +OK: Typed property Foo::$bar must not be accessed before initialization +After __construct: overwritten in constructor + +Test 2: Second __construct() call should fail +OK: Cannot modify readonly property Foo::$bar + +Test 3: Normal 'new' still works +After new: overwritten in constructor +OK: Cannot modify readonly property Foo::$bar + +Test 4: Reflection newInstanceArgs +After newInstanceArgs: overwritten in constructor +OK: Cannot modify readonly property Foo::$bar diff --git a/Zend/tests/readonly_props/cpp_reassign_validation.phpt b/Zend/tests/readonly_props/cpp_reassign_validation.phpt new file mode 100644 index 0000000000000..6539c3ef3316e --- /dev/null +++ b/Zend/tests/readonly_props/cpp_reassign_validation.phpt @@ -0,0 +1,30 @@ +--TEST-- +Promoted readonly property reassignment in constructor - validation +--FILE-- +email = strtolower($email); // Normalize + } +} + +$user = new User('TEST@Example.COM'); +var_dump($user->email); + +try { + new User('not-an-email'); +} catch (InvalidArgumentException $e) { + echo $e->getMessage(), "\n"; +} + +?> +--EXPECT-- +string(16) "test@example.com" +Invalid email diff --git a/Zend/tests/readonly_props/cpp_reassign_visibility.phpt b/Zend/tests/readonly_props/cpp_reassign_visibility.phpt new file mode 100644 index 0000000000000..9a7d552a73543 --- /dev/null +++ b/Zend/tests/readonly_props/cpp_reassign_visibility.phpt @@ -0,0 +1,109 @@ +--TEST-- +Promoted readonly property reassignment in constructor - visibility rules apply +--FILE-- +prop = 'child override'; + } catch (Error $e) { + echo $e->getMessage(), "\n"; + } + } +} + +$child1 = new Child1(); +var_dump($child1->prop); + +// Case 2: protected(set) - child still cannot reassign parent-owned promoted property +class Parent2 { + public function __construct( + protected(set) public readonly string $prop = 'parent default', + ) { + // Parent doesn't use reassignment + } +} + +class Child2 extends Parent2 { + public function __construct() { + parent::__construct(); + try { + $this->prop = 'child override'; + } catch (Error $e) { + echo $e->getMessage(), "\n"; + } + } +} + +$child2 = new Child2(); +var_dump($child2->prop); + +// Case 3: public (default) - child still cannot reassign parent-owned promoted property +class Parent3 { + public function __construct( + public readonly string $prop = 'parent default', + ) { + // Parent doesn't use reassignment + } +} + +class Child3 extends Parent3 { + public function __construct() { + parent::__construct(); + try { + $this->prop = 'child override'; + } catch (Error $e) { + echo $e->getMessage(), "\n"; + } + } +} + +$child3 = new Child3(); +var_dump($child3->prop); + +// Case 4: protected(set) with parent using reassignment - child cannot (one reassignment rule) +class Parent4 { + public function __construct( + protected(set) public readonly string $prop = 'parent default', + ) { + $this->prop = 'parent set'; // Uses the one reassignment + } +} + +class Child4 extends Parent4 { + public function __construct() { + parent::__construct(); + // Child cannot reassign - parent already used the one reassignment + try { + $this->prop = 'child override'; + } catch (Error $e) { + echo $e->getMessage(), "\n"; + } + } +} + +$child4 = new Child4(); +var_dump($child4->prop); + +?> +--EXPECT-- +Cannot modify readonly property Parent1::$prop +string(14) "parent default" +Cannot modify readonly property Parent2::$prop +string(14) "parent default" +Cannot modify readonly property Parent3::$prop +string(14) "parent default" +Cannot modify readonly property Parent4::$prop +string(10) "parent set" diff --git a/Zend/zend_execute.c b/Zend/zend_execute.c index e95931276ef51..c4ce9c56e4ac2 100644 --- a/Zend/zend_execute.c +++ b/Zend/zend_execute.c @@ -1068,14 +1068,16 @@ ZEND_API bool zend_never_inline zend_verify_property_type(const zend_property_in return i_zend_verify_property_type(info, property, strict); } -static zend_never_inline zval* zend_assign_to_typed_prop(const zend_property_info *info, zval *property_val, zval *value, zend_refcounted **garbage_ptr EXECUTE_DATA_DC) +static zend_never_inline zval* zend_assign_to_typed_prop(const zend_property_info *info, zval *property_val, zval *value, zend_refcounted **garbage_ptr, zend_object *zobj EXECUTE_DATA_DC) { zval tmp; if (UNEXPECTED(info->flags & (ZEND_ACC_READONLY|ZEND_ACC_PPP_SET_MASK))) { - if ((info->flags & ZEND_ACC_READONLY) && !(Z_PROP_FLAG_P(property_val) & IS_PROP_REINITABLE)) { - zend_readonly_property_modification_error(info); - return &EG(uninitialized_zval); + if (info->flags & ZEND_ACC_READONLY) { + if (!zend_is_readonly_property_modifiable(property_val, info->ce, zobj)) { + zend_readonly_property_modification_error(info); + return &EG(uninitialized_zval); + } } if (info->flags & ZEND_ACC_PPP_SET_MASK && !zend_asymmetric_property_has_set_access(info)) { zend_asymmetric_visibility_property_modification_error(info, "modify"); @@ -1091,7 +1093,7 @@ static zend_never_inline zval* zend_assign_to_typed_prop(const zend_property_inf return &EG(uninitialized_zval); } - Z_PROP_FLAG_P(property_val) &= ~IS_PROP_REINITABLE; + Z_PROP_FLAG_P(property_val) &= ~(IS_PROP_REINITABLE|IS_PROP_CPP_REINITABLE); return zend_assign_to_variable_ex(property_val, &tmp, IS_TMP_VAR, EX_USES_STRICT_TYPES(), garbage_ptr); } diff --git a/Zend/zend_object_handlers.c b/Zend/zend_object_handlers.c index d1da6de5191f7..6d0e7f27a1ef2 100644 --- a/Zend/zend_object_handlers.c +++ b/Zend/zend_object_handlers.c @@ -46,6 +46,35 @@ #define IN_ISSET ZEND_GUARD_PROPERTY_ISSET #define IN_HOOK ZEND_GUARD_PROPERTY_HOOK +/* Check if we're within a constructor call chain for the given object. + * If ctor_scope is non-NULL, restrict to constructor frames declared by ctor_scope. + * Methods/closures called from that constructor are allowed through the stack walk. */ +static bool zend_is_in_constructor(const zend_object *zobj, const zend_class_entry *ctor_scope) +{ + zend_execute_data *ex = EG(current_execute_data); + while (ex) { + if (ex->func + && (ex->func->common.fn_flags & ZEND_ACC_CTOR) + && (ZEND_CALL_INFO(ex) & ZEND_CALL_HAS_THIS) + && Z_OBJ(ex->This) == zobj + && (!ctor_scope || ex->func->common.scope == ctor_scope)) { + return true; + } + ex = ex->prev_execute_data; + } + return false; +} + +/* Check if we're in the first construction of an object and executing the + * constructor chain declared by ctor_scope. */ +ZEND_API bool zend_is_in_declaring_constructor(const zend_object *zobj, const zend_class_entry *ctor_scope) +{ + if (zobj->extra_flags & IS_OBJ_CTOR_CALLED) { + return false; + } + return zend_is_in_constructor(zobj, ctor_scope); +} + static zend_arg_info zend_call_trampoline_arginfo[1] = {{0}}; static zend_arg_info zend_property_hook_arginfo[1] = {{0}}; @@ -1066,7 +1095,7 @@ ZEND_API zval *zend_std_write_property(zend_object *zobj, zend_string *name, zva if (error) { if ((prop_info->flags & ZEND_ACC_READONLY) && Z_TYPE_P(variable_ptr) != IS_UNDEF - && !(Z_PROP_FLAG_P(variable_ptr) & IS_PROP_REINITABLE)) { + && !zend_is_readonly_property_modifiable(variable_ptr, prop_info->ce, zobj)) { zend_readonly_property_modification_error(prop_info); variable_ptr = &EG(error_zval); goto exit; @@ -1100,7 +1129,15 @@ ZEND_API zval *zend_std_write_property(zend_object *zobj, zend_string *name, zva variable_ptr = &EG(error_zval); goto exit; } - Z_PROP_FLAG_P(variable_ptr) &= ~(IS_PROP_UNINIT|IS_PROP_REINITABLE); + /* For promoted readonly properties being initialized for the first time, + * set IS_PROP_CPP_REINITABLE to allow one reassignment in the constructor. */ + if ((prop_info->flags & (ZEND_ACC_READONLY | ZEND_ACC_PROMOTED)) == (ZEND_ACC_READONLY | ZEND_ACC_PROMOTED) + && (Z_PROP_FLAG_P(variable_ptr) & IS_PROP_UNINIT) + && zend_is_in_declaring_constructor(zobj, prop_info->ce)) { + Z_PROP_FLAG_P(variable_ptr) = IS_PROP_CPP_REINITABLE; + } else { + Z_PROP_FLAG_P(variable_ptr) &= ~(IS_PROP_UNINIT|IS_PROP_REINITABLE|IS_PROP_CPP_REINITABLE); + } value = &tmp; } diff --git a/Zend/zend_object_handlers.h b/Zend/zend_object_handlers.h index 3e922343eb15a..650771517a703 100644 --- a/Zend/zend_object_handlers.h +++ b/Zend/zend_object_handlers.h @@ -276,6 +276,20 @@ ZEND_API zend_result zend_std_get_closure(zend_object *obj, zend_class_entry **c ZEND_API HashTable *rebuild_object_properties_internal(zend_object *zobj); ZEND_API ZEND_COLD zend_never_inline void zend_bad_method_call(const zend_function *fbc, const zend_string *method_name, const zend_class_entry *scope); ZEND_API ZEND_COLD zend_never_inline void zend_abstract_method_call(const zend_function *fbc); +ZEND_API bool zend_is_in_declaring_constructor(const zend_object *zobj, const zend_class_entry *ctor_scope); + +/* Check if a readonly property can be modified (has REINITABLE or CPP_REINITABLE flag and is in constructor) */ +static zend_always_inline bool zend_is_readonly_property_modifiable(zval *property_val, const zend_class_entry *declaring_ce, zend_object *zobj) +{ + if (Z_PROP_FLAG_P(property_val) & IS_PROP_REINITABLE) { + return true; + } + if ((Z_PROP_FLAG_P(property_val) & IS_PROP_CPP_REINITABLE) + && zend_is_in_declaring_constructor(zobj, declaring_ce)) { + return true; + } + return false; +} static zend_always_inline HashTable *zend_std_get_properties_ex(zend_object *object) { diff --git a/Zend/zend_types.h b/Zend/zend_types.h index 22dbfa9be879b..35bc1234ebdcb 100644 --- a/Zend/zend_types.h +++ b/Zend/zend_types.h @@ -858,6 +858,7 @@ static zend_always_inline uint32_t zval_gc_info(uint32_t gc_type_info) { #define IS_OBJ_LAZY_UNINITIALIZED (1U<<31) /* Virtual proxy or uninitialized Ghost */ #define IS_OBJ_LAZY_PROXY (1U<<30) /* Virtual proxy (may be initialized) */ +#define IS_OBJ_CTOR_CALLED (1U<<29) /* A constructor has completed on this object */ #define OBJ_EXTRA_FLAGS(obj) ((obj)->extra_flags) @@ -1594,6 +1595,7 @@ static zend_always_inline uint32_t zval_delref_p(zval* pz) { #define IS_PROP_UNINIT (1<<0) #define IS_PROP_REINITABLE (1<<1) /* It has impact only on readonly properties */ #define IS_PROP_LAZY (1<<2) +#define IS_PROP_CPP_REINITABLE (1<<3) /* Allows one reassignment of promoted readonly property in constructor */ #define Z_PROP_FLAG_P(z) Z_EXTRA_P(z) #define ZVAL_COPY_VALUE_PROP(z, v) \ do { *(z) = *(v); } while (0) diff --git a/Zend/zend_vm_def.h b/Zend/zend_vm_def.h index 2d059159a23c8..aac02617eb5e9 100644 --- a/Zend/zend_vm_def.h +++ b/Zend/zend_vm_def.h @@ -2499,7 +2499,7 @@ ZEND_VM_C_LABEL(assign_obj_simple): property_val = OBJ_PROP(zobj, prop_offset); if (Z_TYPE_P(property_val) != IS_UNDEF) { if (prop_info != NULL) { - value = zend_assign_to_typed_prop(prop_info, property_val, value, &garbage EXECUTE_DATA_CC); + value = zend_assign_to_typed_prop(prop_info, property_val, value, &garbage, zobj EXECUTE_DATA_CC); ZEND_VM_C_GOTO(free_and_exit_assign_obj); } else { ZEND_VM_C_LABEL(fast_assign_obj): @@ -2634,7 +2634,7 @@ ZEND_VM_HANDLER(25, ZEND_ASSIGN_STATIC_PROP, ANY, ANY, CACHE_SLOT, SPEC(OP_DATA= value = GET_OP_DATA_ZVAL_PTR(BP_VAR_R); if (ZEND_TYPE_IS_SET(prop_info->type)) { - value = zend_assign_to_typed_prop(prop_info, prop, value, &garbage EXECUTE_DATA_CC); + value = zend_assign_to_typed_prop(prop_info, prop, value, &garbage, NULL EXECUTE_DATA_CC); FREE_OP_DATA(); } else { value = zend_assign_to_variable_ex(prop, value, OP_DATA_TYPE, EX_USES_STRICT_TYPES(), &garbage); @@ -2975,7 +2975,12 @@ ZEND_VM_HOT_HELPER(zend_leave_helper, ANY, ANY) call_info = EX_CALL_INFO(); #endif if (UNEXPECTED(call_info & ZEND_CALL_RELEASE_THIS)) { - OBJ_RELEASE(Z_OBJ(execute_data->This)); + zend_object *obj = Z_OBJ(execute_data->This); + /* Mark that a constructor has completed on this object */ + if (EX(func)->common.fn_flags & ZEND_ACC_CTOR) { + obj->extra_flags |= IS_OBJ_CTOR_CALLED; + } + OBJ_RELEASE(obj); } else if (UNEXPECTED(call_info & ZEND_CALL_CLOSURE)) { OBJ_RELEASE(ZEND_CLOSURE_OBJECT(EX(func))); } @@ -3009,7 +3014,12 @@ ZEND_VM_HOT_HELPER(zend_leave_helper, ANY, ANY) zend_vm_stack_free_extra_args_ex(call_info, execute_data); if (UNEXPECTED(call_info & ZEND_CALL_RELEASE_THIS)) { - OBJ_RELEASE(Z_OBJ(execute_data->This)); + zend_object *obj = Z_OBJ(execute_data->This); + /* Mark that a constructor has completed on this object */ + if (EX(func)->common.fn_flags & ZEND_ACC_CTOR) { + obj->extra_flags |= IS_OBJ_CTOR_CALLED; + } + OBJ_RELEASE(obj); } else if (UNEXPECTED(call_info & ZEND_CALL_CLOSURE)) { OBJ_RELEASE(ZEND_CLOSURE_OBJECT(EX(func))); } diff --git a/Zend/zend_vm_execute.h b/Zend/zend_vm_execute.h index 38b869c4a4c07..480474f22337e 100644 --- a/Zend/zend_vm_execute.h +++ b/Zend/zend_vm_execute.h @@ -1001,7 +1001,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_OPCODE_HANDLER_FUNC_CCONV ZEND_ASSIGN_STATIC value = RT_CONSTANT((opline+1), (opline+1)->op1); if (ZEND_TYPE_IS_SET(prop_info->type)) { - value = zend_assign_to_typed_prop(prop_info, prop, value, &garbage EXECUTE_DATA_CC); + value = zend_assign_to_typed_prop(prop_info, prop, value, &garbage, NULL EXECUTE_DATA_CC); } else { @@ -1039,7 +1039,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_OPCODE_HANDLER_FUNC_CCONV ZEND_ASSIGN_STATIC value = _get_zval_ptr_tmp((opline+1)->op1.var EXECUTE_DATA_CC); if (ZEND_TYPE_IS_SET(prop_info->type)) { - value = zend_assign_to_typed_prop(prop_info, prop, value, &garbage EXECUTE_DATA_CC); + value = zend_assign_to_typed_prop(prop_info, prop, value, &garbage, NULL EXECUTE_DATA_CC); zval_ptr_dtor_nogc(EX_VAR((opline+1)->op1.var)); } else { value = zend_assign_to_variable_ex(prop, value, IS_TMP_VAR, EX_USES_STRICT_TYPES(), &garbage); @@ -1076,7 +1076,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_OPCODE_HANDLER_FUNC_CCONV ZEND_ASSIGN_STATIC value = _get_zval_ptr_var((opline+1)->op1.var EXECUTE_DATA_CC); if (ZEND_TYPE_IS_SET(prop_info->type)) { - value = zend_assign_to_typed_prop(prop_info, prop, value, &garbage EXECUTE_DATA_CC); + value = zend_assign_to_typed_prop(prop_info, prop, value, &garbage, NULL EXECUTE_DATA_CC); zval_ptr_dtor_nogc(EX_VAR((opline+1)->op1.var)); } else { value = zend_assign_to_variable_ex(prop, value, IS_VAR, EX_USES_STRICT_TYPES(), &garbage); @@ -1114,7 +1114,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_OPCODE_HANDLER_FUNC_CCONV ZEND_ASSIGN_STATIC value = _get_zval_ptr_cv_BP_VAR_R((opline+1)->op1.var EXECUTE_DATA_CC); if (ZEND_TYPE_IS_SET(prop_info->type)) { - value = zend_assign_to_typed_prop(prop_info, prop, value, &garbage EXECUTE_DATA_CC); + value = zend_assign_to_typed_prop(prop_info, prop, value, &garbage, NULL EXECUTE_DATA_CC); } else { @@ -1198,7 +1198,12 @@ static zend_never_inline ZEND_OPCODE_HANDLER_RET ZEND_OPCODE_HANDLER_FUNC_CCONV call_info = EX_CALL_INFO(); #endif if (UNEXPECTED(call_info & ZEND_CALL_RELEASE_THIS)) { - OBJ_RELEASE(Z_OBJ(execute_data->This)); + zend_object *obj = Z_OBJ(execute_data->This); + /* Mark that a constructor has completed on this object */ + if (EX(func)->common.fn_flags & ZEND_ACC_CTOR) { + obj->extra_flags |= IS_OBJ_CTOR_CALLED; + } + OBJ_RELEASE(obj); } else if (UNEXPECTED(call_info & ZEND_CALL_CLOSURE)) { OBJ_RELEASE(ZEND_CLOSURE_OBJECT(EX(func))); } @@ -1232,7 +1237,12 @@ static zend_never_inline ZEND_OPCODE_HANDLER_RET ZEND_OPCODE_HANDLER_FUNC_CCONV zend_vm_stack_free_extra_args_ex(call_info, execute_data); if (UNEXPECTED(call_info & ZEND_CALL_RELEASE_THIS)) { - OBJ_RELEASE(Z_OBJ(execute_data->This)); + zend_object *obj = Z_OBJ(execute_data->This); + /* Mark that a constructor has completed on this object */ + if (EX(func)->common.fn_flags & ZEND_ACC_CTOR) { + obj->extra_flags |= IS_OBJ_CTOR_CALLED; + } + OBJ_RELEASE(obj); } else if (UNEXPECTED(call_info & ZEND_CALL_CLOSURE)) { OBJ_RELEASE(ZEND_CLOSURE_OBJECT(EX(func))); } @@ -24682,7 +24692,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_OPCODE_HANDLER_FUNC_CCONV ZEND_ASSIGN_OBJ_SP property_val = OBJ_PROP(zobj, prop_offset); if (Z_TYPE_P(property_val) != IS_UNDEF) { if (prop_info != NULL) { - value = zend_assign_to_typed_prop(prop_info, property_val, value, &garbage EXECUTE_DATA_CC); + value = zend_assign_to_typed_prop(prop_info, property_val, value, &garbage, zobj EXECUTE_DATA_CC); goto free_and_exit_assign_obj; } else { fast_assign_obj: @@ -24839,7 +24849,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_OPCODE_HANDLER_FUNC_CCONV ZEND_ASSIGN_OBJ_SP property_val = OBJ_PROP(zobj, prop_offset); if (Z_TYPE_P(property_val) != IS_UNDEF) { if (prop_info != NULL) { - value = zend_assign_to_typed_prop(prop_info, property_val, value, &garbage EXECUTE_DATA_CC); + value = zend_assign_to_typed_prop(prop_info, property_val, value, &garbage, zobj EXECUTE_DATA_CC); goto free_and_exit_assign_obj; } else { fast_assign_obj: @@ -24994,7 +25004,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_OPCODE_HANDLER_FUNC_CCONV ZEND_ASSIGN_OBJ_SP property_val = OBJ_PROP(zobj, prop_offset); if (Z_TYPE_P(property_val) != IS_UNDEF) { if (prop_info != NULL) { - value = zend_assign_to_typed_prop(prop_info, property_val, value, &garbage EXECUTE_DATA_CC); + value = zend_assign_to_typed_prop(prop_info, property_val, value, &garbage, zobj EXECUTE_DATA_CC); goto free_and_exit_assign_obj; } else { fast_assign_obj: @@ -25149,7 +25159,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_OPCODE_HANDLER_FUNC_CCONV ZEND_ASSIGN_OBJ_SP property_val = OBJ_PROP(zobj, prop_offset); if (Z_TYPE_P(property_val) != IS_UNDEF) { if (prop_info != NULL) { - value = zend_assign_to_typed_prop(prop_info, property_val, value, &garbage EXECUTE_DATA_CC); + value = zend_assign_to_typed_prop(prop_info, property_val, value, &garbage, zobj EXECUTE_DATA_CC); goto free_and_exit_assign_obj; } else { fast_assign_obj: @@ -27757,7 +27767,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_OPCODE_HANDLER_FUNC_CCONV ZEND_ASSIGN_OBJ_SP property_val = OBJ_PROP(zobj, prop_offset); if (Z_TYPE_P(property_val) != IS_UNDEF) { if (prop_info != NULL) { - value = zend_assign_to_typed_prop(prop_info, property_val, value, &garbage EXECUTE_DATA_CC); + value = zend_assign_to_typed_prop(prop_info, property_val, value, &garbage, zobj EXECUTE_DATA_CC); goto free_and_exit_assign_obj; } else { fast_assign_obj: @@ -27913,7 +27923,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_OPCODE_HANDLER_FUNC_CCONV ZEND_ASSIGN_OBJ_SP property_val = OBJ_PROP(zobj, prop_offset); if (Z_TYPE_P(property_val) != IS_UNDEF) { if (prop_info != NULL) { - value = zend_assign_to_typed_prop(prop_info, property_val, value, &garbage EXECUTE_DATA_CC); + value = zend_assign_to_typed_prop(prop_info, property_val, value, &garbage, zobj EXECUTE_DATA_CC); goto free_and_exit_assign_obj; } else { fast_assign_obj: @@ -28067,7 +28077,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_OPCODE_HANDLER_FUNC_CCONV ZEND_ASSIGN_OBJ_SP property_val = OBJ_PROP(zobj, prop_offset); if (Z_TYPE_P(property_val) != IS_UNDEF) { if (prop_info != NULL) { - value = zend_assign_to_typed_prop(prop_info, property_val, value, &garbage EXECUTE_DATA_CC); + value = zend_assign_to_typed_prop(prop_info, property_val, value, &garbage, zobj EXECUTE_DATA_CC); goto free_and_exit_assign_obj; } else { fast_assign_obj: @@ -28221,7 +28231,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_OPCODE_HANDLER_FUNC_CCONV ZEND_ASSIGN_OBJ_SP property_val = OBJ_PROP(zobj, prop_offset); if (Z_TYPE_P(property_val) != IS_UNDEF) { if (prop_info != NULL) { - value = zend_assign_to_typed_prop(prop_info, property_val, value, &garbage EXECUTE_DATA_CC); + value = zend_assign_to_typed_prop(prop_info, property_val, value, &garbage, zobj EXECUTE_DATA_CC); goto free_and_exit_assign_obj; } else { fast_assign_obj: @@ -32201,7 +32211,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_OPCODE_HANDLER_FUNC_CCONV ZEND_ASSIGN_OBJ_SP property_val = OBJ_PROP(zobj, prop_offset); if (Z_TYPE_P(property_val) != IS_UNDEF) { if (prop_info != NULL) { - value = zend_assign_to_typed_prop(prop_info, property_val, value, &garbage EXECUTE_DATA_CC); + value = zend_assign_to_typed_prop(prop_info, property_val, value, &garbage, zobj EXECUTE_DATA_CC); goto free_and_exit_assign_obj; } else { fast_assign_obj: @@ -32358,7 +32368,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_OPCODE_HANDLER_FUNC_CCONV ZEND_ASSIGN_OBJ_SP property_val = OBJ_PROP(zobj, prop_offset); if (Z_TYPE_P(property_val) != IS_UNDEF) { if (prop_info != NULL) { - value = zend_assign_to_typed_prop(prop_info, property_val, value, &garbage EXECUTE_DATA_CC); + value = zend_assign_to_typed_prop(prop_info, property_val, value, &garbage, zobj EXECUTE_DATA_CC); goto free_and_exit_assign_obj; } else { fast_assign_obj: @@ -32513,7 +32523,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_OPCODE_HANDLER_FUNC_CCONV ZEND_ASSIGN_OBJ_SP property_val = OBJ_PROP(zobj, prop_offset); if (Z_TYPE_P(property_val) != IS_UNDEF) { if (prop_info != NULL) { - value = zend_assign_to_typed_prop(prop_info, property_val, value, &garbage EXECUTE_DATA_CC); + value = zend_assign_to_typed_prop(prop_info, property_val, value, &garbage, zobj EXECUTE_DATA_CC); goto free_and_exit_assign_obj; } else { fast_assign_obj: @@ -32668,7 +32678,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_OPCODE_HANDLER_FUNC_CCONV ZEND_ASSIGN_OBJ_SP property_val = OBJ_PROP(zobj, prop_offset); if (Z_TYPE_P(property_val) != IS_UNDEF) { if (prop_info != NULL) { - value = zend_assign_to_typed_prop(prop_info, property_val, value, &garbage EXECUTE_DATA_CC); + value = zend_assign_to_typed_prop(prop_info, property_val, value, &garbage, zobj EXECUTE_DATA_CC); goto free_and_exit_assign_obj; } else { fast_assign_obj: @@ -35030,7 +35040,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_OPCODE_HANDLER_FUNC_CCONV ZEND_ASSIGN_OBJ_SP property_val = OBJ_PROP(zobj, prop_offset); if (Z_TYPE_P(property_val) != IS_UNDEF) { if (prop_info != NULL) { - value = zend_assign_to_typed_prop(prop_info, property_val, value, &garbage EXECUTE_DATA_CC); + value = zend_assign_to_typed_prop(prop_info, property_val, value, &garbage, zobj EXECUTE_DATA_CC); goto free_and_exit_assign_obj; } else { fast_assign_obj: @@ -35188,7 +35198,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_OPCODE_HANDLER_FUNC_CCONV ZEND_ASSIGN_OBJ_SP property_val = OBJ_PROP(zobj, prop_offset); if (Z_TYPE_P(property_val) != IS_UNDEF) { if (prop_info != NULL) { - value = zend_assign_to_typed_prop(prop_info, property_val, value, &garbage EXECUTE_DATA_CC); + value = zend_assign_to_typed_prop(prop_info, property_val, value, &garbage, zobj EXECUTE_DATA_CC); goto free_and_exit_assign_obj; } else { fast_assign_obj: @@ -35344,7 +35354,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_OPCODE_HANDLER_FUNC_CCONV ZEND_ASSIGN_OBJ_SP property_val = OBJ_PROP(zobj, prop_offset); if (Z_TYPE_P(property_val) != IS_UNDEF) { if (prop_info != NULL) { - value = zend_assign_to_typed_prop(prop_info, property_val, value, &garbage EXECUTE_DATA_CC); + value = zend_assign_to_typed_prop(prop_info, property_val, value, &garbage, zobj EXECUTE_DATA_CC); goto free_and_exit_assign_obj; } else { fast_assign_obj: @@ -35500,7 +35510,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_OPCODE_HANDLER_FUNC_CCONV ZEND_ASSIGN_OBJ_SP property_val = OBJ_PROP(zobj, prop_offset); if (Z_TYPE_P(property_val) != IS_UNDEF) { if (prop_info != NULL) { - value = zend_assign_to_typed_prop(prop_info, property_val, value, &garbage EXECUTE_DATA_CC); + value = zend_assign_to_typed_prop(prop_info, property_val, value, &garbage, zobj EXECUTE_DATA_CC); goto free_and_exit_assign_obj; } else { fast_assign_obj: @@ -37270,7 +37280,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_OPCODE_HANDLER_FUNC_CCONV ZEND_ASSIGN_OBJ_SP property_val = OBJ_PROP(zobj, prop_offset); if (Z_TYPE_P(property_val) != IS_UNDEF) { if (prop_info != NULL) { - value = zend_assign_to_typed_prop(prop_info, property_val, value, &garbage EXECUTE_DATA_CC); + value = zend_assign_to_typed_prop(prop_info, property_val, value, &garbage, zobj EXECUTE_DATA_CC); goto free_and_exit_assign_obj; } else { fast_assign_obj: @@ -37427,7 +37437,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_OPCODE_HANDLER_FUNC_CCONV ZEND_ASSIGN_OBJ_SP property_val = OBJ_PROP(zobj, prop_offset); if (Z_TYPE_P(property_val) != IS_UNDEF) { if (prop_info != NULL) { - value = zend_assign_to_typed_prop(prop_info, property_val, value, &garbage EXECUTE_DATA_CC); + value = zend_assign_to_typed_prop(prop_info, property_val, value, &garbage, zobj EXECUTE_DATA_CC); goto free_and_exit_assign_obj; } else { fast_assign_obj: @@ -37582,7 +37592,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_OPCODE_HANDLER_FUNC_CCONV ZEND_ASSIGN_OBJ_SP property_val = OBJ_PROP(zobj, prop_offset); if (Z_TYPE_P(property_val) != IS_UNDEF) { if (prop_info != NULL) { - value = zend_assign_to_typed_prop(prop_info, property_val, value, &garbage EXECUTE_DATA_CC); + value = zend_assign_to_typed_prop(prop_info, property_val, value, &garbage, zobj EXECUTE_DATA_CC); goto free_and_exit_assign_obj; } else { fast_assign_obj: @@ -37737,7 +37747,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_OPCODE_HANDLER_FUNC_CCONV ZEND_ASSIGN_OBJ_SP property_val = OBJ_PROP(zobj, prop_offset); if (Z_TYPE_P(property_val) != IS_UNDEF) { if (prop_info != NULL) { - value = zend_assign_to_typed_prop(prop_info, property_val, value, &garbage EXECUTE_DATA_CC); + value = zend_assign_to_typed_prop(prop_info, property_val, value, &garbage, zobj EXECUTE_DATA_CC); goto free_and_exit_assign_obj; } else { fast_assign_obj: @@ -39980,7 +39990,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_OPCODE_HANDLER_FUNC_CCONV ZEND_ASSIGN_OBJ_SP property_val = OBJ_PROP(zobj, prop_offset); if (Z_TYPE_P(property_val) != IS_UNDEF) { if (prop_info != NULL) { - value = zend_assign_to_typed_prop(prop_info, property_val, value, &garbage EXECUTE_DATA_CC); + value = zend_assign_to_typed_prop(prop_info, property_val, value, &garbage, zobj EXECUTE_DATA_CC); goto free_and_exit_assign_obj; } else { fast_assign_obj: @@ -40138,7 +40148,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_OPCODE_HANDLER_FUNC_CCONV ZEND_ASSIGN_OBJ_SP property_val = OBJ_PROP(zobj, prop_offset); if (Z_TYPE_P(property_val) != IS_UNDEF) { if (prop_info != NULL) { - value = zend_assign_to_typed_prop(prop_info, property_val, value, &garbage EXECUTE_DATA_CC); + value = zend_assign_to_typed_prop(prop_info, property_val, value, &garbage, zobj EXECUTE_DATA_CC); goto free_and_exit_assign_obj; } else { fast_assign_obj: @@ -40294,7 +40304,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_OPCODE_HANDLER_FUNC_CCONV ZEND_ASSIGN_OBJ_SP property_val = OBJ_PROP(zobj, prop_offset); if (Z_TYPE_P(property_val) != IS_UNDEF) { if (prop_info != NULL) { - value = zend_assign_to_typed_prop(prop_info, property_val, value, &garbage EXECUTE_DATA_CC); + value = zend_assign_to_typed_prop(prop_info, property_val, value, &garbage, zobj EXECUTE_DATA_CC); goto free_and_exit_assign_obj; } else { fast_assign_obj: @@ -40450,7 +40460,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_OPCODE_HANDLER_FUNC_CCONV ZEND_ASSIGN_OBJ_SP property_val = OBJ_PROP(zobj, prop_offset); if (Z_TYPE_P(property_val) != IS_UNDEF) { if (prop_info != NULL) { - value = zend_assign_to_typed_prop(prop_info, property_val, value, &garbage EXECUTE_DATA_CC); + value = zend_assign_to_typed_prop(prop_info, property_val, value, &garbage, zobj EXECUTE_DATA_CC); goto free_and_exit_assign_obj; } else { fast_assign_obj: @@ -44477,7 +44487,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_OPCODE_HANDLER_FUNC_CCONV ZEND_ASSIGN_OBJ_SP property_val = OBJ_PROP(zobj, prop_offset); if (Z_TYPE_P(property_val) != IS_UNDEF) { if (prop_info != NULL) { - value = zend_assign_to_typed_prop(prop_info, property_val, value, &garbage EXECUTE_DATA_CC); + value = zend_assign_to_typed_prop(prop_info, property_val, value, &garbage, zobj EXECUTE_DATA_CC); goto free_and_exit_assign_obj; } else { fast_assign_obj: @@ -44635,7 +44645,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_OPCODE_HANDLER_FUNC_CCONV ZEND_ASSIGN_OBJ_SP property_val = OBJ_PROP(zobj, prop_offset); if (Z_TYPE_P(property_val) != IS_UNDEF) { if (prop_info != NULL) { - value = zend_assign_to_typed_prop(prop_info, property_val, value, &garbage EXECUTE_DATA_CC); + value = zend_assign_to_typed_prop(prop_info, property_val, value, &garbage, zobj EXECUTE_DATA_CC); goto free_and_exit_assign_obj; } else { fast_assign_obj: @@ -44791,7 +44801,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_OPCODE_HANDLER_FUNC_CCONV ZEND_ASSIGN_OBJ_SP property_val = OBJ_PROP(zobj, prop_offset); if (Z_TYPE_P(property_val) != IS_UNDEF) { if (prop_info != NULL) { - value = zend_assign_to_typed_prop(prop_info, property_val, value, &garbage EXECUTE_DATA_CC); + value = zend_assign_to_typed_prop(prop_info, property_val, value, &garbage, zobj EXECUTE_DATA_CC); goto free_and_exit_assign_obj; } else { fast_assign_obj: @@ -44947,7 +44957,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_OPCODE_HANDLER_FUNC_CCONV ZEND_ASSIGN_OBJ_SP property_val = OBJ_PROP(zobj, prop_offset); if (Z_TYPE_P(property_val) != IS_UNDEF) { if (prop_info != NULL) { - value = zend_assign_to_typed_prop(prop_info, property_val, value, &garbage EXECUTE_DATA_CC); + value = zend_assign_to_typed_prop(prop_info, property_val, value, &garbage, zobj EXECUTE_DATA_CC); goto free_and_exit_assign_obj; } else { fast_assign_obj: @@ -48553,7 +48563,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_OPCODE_HANDLER_FUNC_CCONV ZEND_ASSIGN_OBJ_SP property_val = OBJ_PROP(zobj, prop_offset); if (Z_TYPE_P(property_val) != IS_UNDEF) { if (prop_info != NULL) { - value = zend_assign_to_typed_prop(prop_info, property_val, value, &garbage EXECUTE_DATA_CC); + value = zend_assign_to_typed_prop(prop_info, property_val, value, &garbage, zobj EXECUTE_DATA_CC); goto free_and_exit_assign_obj; } else { fast_assign_obj: @@ -48710,7 +48720,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_OPCODE_HANDLER_FUNC_CCONV ZEND_ASSIGN_OBJ_SP property_val = OBJ_PROP(zobj, prop_offset); if (Z_TYPE_P(property_val) != IS_UNDEF) { if (prop_info != NULL) { - value = zend_assign_to_typed_prop(prop_info, property_val, value, &garbage EXECUTE_DATA_CC); + value = zend_assign_to_typed_prop(prop_info, property_val, value, &garbage, zobj EXECUTE_DATA_CC); goto free_and_exit_assign_obj; } else { fast_assign_obj: @@ -48865,7 +48875,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_OPCODE_HANDLER_FUNC_CCONV ZEND_ASSIGN_OBJ_SP property_val = OBJ_PROP(zobj, prop_offset); if (Z_TYPE_P(property_val) != IS_UNDEF) { if (prop_info != NULL) { - value = zend_assign_to_typed_prop(prop_info, property_val, value, &garbage EXECUTE_DATA_CC); + value = zend_assign_to_typed_prop(prop_info, property_val, value, &garbage, zobj EXECUTE_DATA_CC); goto free_and_exit_assign_obj; } else { fast_assign_obj: @@ -49020,7 +49030,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_OPCODE_HANDLER_FUNC_CCONV ZEND_ASSIGN_OBJ_SP property_val = OBJ_PROP(zobj, prop_offset); if (Z_TYPE_P(property_val) != IS_UNDEF) { if (prop_info != NULL) { - value = zend_assign_to_typed_prop(prop_info, property_val, value, &garbage EXECUTE_DATA_CC); + value = zend_assign_to_typed_prop(prop_info, property_val, value, &garbage, zobj EXECUTE_DATA_CC); goto free_and_exit_assign_obj; } else { fast_assign_obj: @@ -54223,7 +54233,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_OPCODE_HANDLER_FUNC_CCONV ZEND_ASSIGN_OBJ_SP property_val = OBJ_PROP(zobj, prop_offset); if (Z_TYPE_P(property_val) != IS_UNDEF) { if (prop_info != NULL) { - value = zend_assign_to_typed_prop(prop_info, property_val, value, &garbage EXECUTE_DATA_CC); + value = zend_assign_to_typed_prop(prop_info, property_val, value, &garbage, zobj EXECUTE_DATA_CC); goto free_and_exit_assign_obj; } else { fast_assign_obj: @@ -54381,7 +54391,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_OPCODE_HANDLER_FUNC_CCONV ZEND_ASSIGN_OBJ_SP property_val = OBJ_PROP(zobj, prop_offset); if (Z_TYPE_P(property_val) != IS_UNDEF) { if (prop_info != NULL) { - value = zend_assign_to_typed_prop(prop_info, property_val, value, &garbage EXECUTE_DATA_CC); + value = zend_assign_to_typed_prop(prop_info, property_val, value, &garbage, zobj EXECUTE_DATA_CC); goto free_and_exit_assign_obj; } else { fast_assign_obj: @@ -54537,7 +54547,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_OPCODE_HANDLER_FUNC_CCONV ZEND_ASSIGN_OBJ_SP property_val = OBJ_PROP(zobj, prop_offset); if (Z_TYPE_P(property_val) != IS_UNDEF) { if (prop_info != NULL) { - value = zend_assign_to_typed_prop(prop_info, property_val, value, &garbage EXECUTE_DATA_CC); + value = zend_assign_to_typed_prop(prop_info, property_val, value, &garbage, zobj EXECUTE_DATA_CC); goto free_and_exit_assign_obj; } else { fast_assign_obj: @@ -54693,7 +54703,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_OPCODE_HANDLER_FUNC_CCONV ZEND_ASSIGN_OBJ_SP property_val = OBJ_PROP(zobj, prop_offset); if (Z_TYPE_P(property_val) != IS_UNDEF) { if (prop_info != NULL) { - value = zend_assign_to_typed_prop(prop_info, property_val, value, &garbage EXECUTE_DATA_CC); + value = zend_assign_to_typed_prop(prop_info, property_val, value, &garbage, zobj EXECUTE_DATA_CC); goto free_and_exit_assign_obj; } else { fast_assign_obj: @@ -56801,7 +56811,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_OPCODE_HANDLER_CCONV ZEND_ASSIGN_STATIC_PROP value = RT_CONSTANT((opline+1), (opline+1)->op1); if (ZEND_TYPE_IS_SET(prop_info->type)) { - value = zend_assign_to_typed_prop(prop_info, prop, value, &garbage EXECUTE_DATA_CC); + value = zend_assign_to_typed_prop(prop_info, prop, value, &garbage, NULL EXECUTE_DATA_CC); } else { @@ -56839,7 +56849,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_OPCODE_HANDLER_CCONV ZEND_ASSIGN_STATIC_PROP value = _get_zval_ptr_tmp((opline+1)->op1.var EXECUTE_DATA_CC); if (ZEND_TYPE_IS_SET(prop_info->type)) { - value = zend_assign_to_typed_prop(prop_info, prop, value, &garbage EXECUTE_DATA_CC); + value = zend_assign_to_typed_prop(prop_info, prop, value, &garbage, NULL EXECUTE_DATA_CC); zval_ptr_dtor_nogc(EX_VAR((opline+1)->op1.var)); } else { value = zend_assign_to_variable_ex(prop, value, IS_TMP_VAR, EX_USES_STRICT_TYPES(), &garbage); @@ -56876,7 +56886,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_OPCODE_HANDLER_CCONV ZEND_ASSIGN_STATIC_PROP value = _get_zval_ptr_var((opline+1)->op1.var EXECUTE_DATA_CC); if (ZEND_TYPE_IS_SET(prop_info->type)) { - value = zend_assign_to_typed_prop(prop_info, prop, value, &garbage EXECUTE_DATA_CC); + value = zend_assign_to_typed_prop(prop_info, prop, value, &garbage, NULL EXECUTE_DATA_CC); zval_ptr_dtor_nogc(EX_VAR((opline+1)->op1.var)); } else { value = zend_assign_to_variable_ex(prop, value, IS_VAR, EX_USES_STRICT_TYPES(), &garbage); @@ -56914,7 +56924,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_OPCODE_HANDLER_CCONV ZEND_ASSIGN_STATIC_PROP value = _get_zval_ptr_cv_BP_VAR_R((opline+1)->op1.var EXECUTE_DATA_CC); if (ZEND_TYPE_IS_SET(prop_info->type)) { - value = zend_assign_to_typed_prop(prop_info, prop, value, &garbage EXECUTE_DATA_CC); + value = zend_assign_to_typed_prop(prop_info, prop, value, &garbage, NULL EXECUTE_DATA_CC); } else { @@ -56998,7 +57008,12 @@ static zend_never_inline ZEND_OPCODE_HANDLER_RET ZEND_OPCODE_HANDLER_CCONV zend call_info = EX_CALL_INFO(); #endif if (UNEXPECTED(call_info & ZEND_CALL_RELEASE_THIS)) { - OBJ_RELEASE(Z_OBJ(execute_data->This)); + zend_object *obj = Z_OBJ(execute_data->This); + /* Mark that a constructor has completed on this object */ + if (EX(func)->common.fn_flags & ZEND_ACC_CTOR) { + obj->extra_flags |= IS_OBJ_CTOR_CALLED; + } + OBJ_RELEASE(obj); } else if (UNEXPECTED(call_info & ZEND_CALL_CLOSURE)) { OBJ_RELEASE(ZEND_CLOSURE_OBJECT(EX(func))); } @@ -57032,7 +57047,12 @@ static zend_never_inline ZEND_OPCODE_HANDLER_RET ZEND_OPCODE_HANDLER_CCONV zend zend_vm_stack_free_extra_args_ex(call_info, execute_data); if (UNEXPECTED(call_info & ZEND_CALL_RELEASE_THIS)) { - OBJ_RELEASE(Z_OBJ(execute_data->This)); + zend_object *obj = Z_OBJ(execute_data->This); + /* Mark that a constructor has completed on this object */ + if (EX(func)->common.fn_flags & ZEND_ACC_CTOR) { + obj->extra_flags |= IS_OBJ_CTOR_CALLED; + } + OBJ_RELEASE(obj); } else if (UNEXPECTED(call_info & ZEND_CALL_CLOSURE)) { OBJ_RELEASE(ZEND_CLOSURE_OBJECT(EX(func))); } @@ -80164,7 +80184,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_OPCODE_HANDLER_CCONV ZEND_ASSIGN_OBJ_SPEC_VA property_val = OBJ_PROP(zobj, prop_offset); if (Z_TYPE_P(property_val) != IS_UNDEF) { if (prop_info != NULL) { - value = zend_assign_to_typed_prop(prop_info, property_val, value, &garbage EXECUTE_DATA_CC); + value = zend_assign_to_typed_prop(prop_info, property_val, value, &garbage, zobj EXECUTE_DATA_CC); goto free_and_exit_assign_obj; } else { fast_assign_obj: @@ -80321,7 +80341,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_OPCODE_HANDLER_CCONV ZEND_ASSIGN_OBJ_SPEC_VA property_val = OBJ_PROP(zobj, prop_offset); if (Z_TYPE_P(property_val) != IS_UNDEF) { if (prop_info != NULL) { - value = zend_assign_to_typed_prop(prop_info, property_val, value, &garbage EXECUTE_DATA_CC); + value = zend_assign_to_typed_prop(prop_info, property_val, value, &garbage, zobj EXECUTE_DATA_CC); goto free_and_exit_assign_obj; } else { fast_assign_obj: @@ -80476,7 +80496,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_OPCODE_HANDLER_CCONV ZEND_ASSIGN_OBJ_SPEC_VA property_val = OBJ_PROP(zobj, prop_offset); if (Z_TYPE_P(property_val) != IS_UNDEF) { if (prop_info != NULL) { - value = zend_assign_to_typed_prop(prop_info, property_val, value, &garbage EXECUTE_DATA_CC); + value = zend_assign_to_typed_prop(prop_info, property_val, value, &garbage, zobj EXECUTE_DATA_CC); goto free_and_exit_assign_obj; } else { fast_assign_obj: @@ -80631,7 +80651,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_OPCODE_HANDLER_CCONV ZEND_ASSIGN_OBJ_SPEC_VA property_val = OBJ_PROP(zobj, prop_offset); if (Z_TYPE_P(property_val) != IS_UNDEF) { if (prop_info != NULL) { - value = zend_assign_to_typed_prop(prop_info, property_val, value, &garbage EXECUTE_DATA_CC); + value = zend_assign_to_typed_prop(prop_info, property_val, value, &garbage, zobj EXECUTE_DATA_CC); goto free_and_exit_assign_obj; } else { fast_assign_obj: @@ -83239,7 +83259,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_OPCODE_HANDLER_CCONV ZEND_ASSIGN_OBJ_SPEC_VA property_val = OBJ_PROP(zobj, prop_offset); if (Z_TYPE_P(property_val) != IS_UNDEF) { if (prop_info != NULL) { - value = zend_assign_to_typed_prop(prop_info, property_val, value, &garbage EXECUTE_DATA_CC); + value = zend_assign_to_typed_prop(prop_info, property_val, value, &garbage, zobj EXECUTE_DATA_CC); goto free_and_exit_assign_obj; } else { fast_assign_obj: @@ -83395,7 +83415,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_OPCODE_HANDLER_CCONV ZEND_ASSIGN_OBJ_SPEC_VA property_val = OBJ_PROP(zobj, prop_offset); if (Z_TYPE_P(property_val) != IS_UNDEF) { if (prop_info != NULL) { - value = zend_assign_to_typed_prop(prop_info, property_val, value, &garbage EXECUTE_DATA_CC); + value = zend_assign_to_typed_prop(prop_info, property_val, value, &garbage, zobj EXECUTE_DATA_CC); goto free_and_exit_assign_obj; } else { fast_assign_obj: @@ -83549,7 +83569,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_OPCODE_HANDLER_CCONV ZEND_ASSIGN_OBJ_SPEC_VA property_val = OBJ_PROP(zobj, prop_offset); if (Z_TYPE_P(property_val) != IS_UNDEF) { if (prop_info != NULL) { - value = zend_assign_to_typed_prop(prop_info, property_val, value, &garbage EXECUTE_DATA_CC); + value = zend_assign_to_typed_prop(prop_info, property_val, value, &garbage, zobj EXECUTE_DATA_CC); goto free_and_exit_assign_obj; } else { fast_assign_obj: @@ -83703,7 +83723,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_OPCODE_HANDLER_CCONV ZEND_ASSIGN_OBJ_SPEC_VA property_val = OBJ_PROP(zobj, prop_offset); if (Z_TYPE_P(property_val) != IS_UNDEF) { if (prop_info != NULL) { - value = zend_assign_to_typed_prop(prop_info, property_val, value, &garbage EXECUTE_DATA_CC); + value = zend_assign_to_typed_prop(prop_info, property_val, value, &garbage, zobj EXECUTE_DATA_CC); goto free_and_exit_assign_obj; } else { fast_assign_obj: @@ -87683,7 +87703,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_OPCODE_HANDLER_CCONV ZEND_ASSIGN_OBJ_SPEC_VA property_val = OBJ_PROP(zobj, prop_offset); if (Z_TYPE_P(property_val) != IS_UNDEF) { if (prop_info != NULL) { - value = zend_assign_to_typed_prop(prop_info, property_val, value, &garbage EXECUTE_DATA_CC); + value = zend_assign_to_typed_prop(prop_info, property_val, value, &garbage, zobj EXECUTE_DATA_CC); goto free_and_exit_assign_obj; } else { fast_assign_obj: @@ -87840,7 +87860,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_OPCODE_HANDLER_CCONV ZEND_ASSIGN_OBJ_SPEC_VA property_val = OBJ_PROP(zobj, prop_offset); if (Z_TYPE_P(property_val) != IS_UNDEF) { if (prop_info != NULL) { - value = zend_assign_to_typed_prop(prop_info, property_val, value, &garbage EXECUTE_DATA_CC); + value = zend_assign_to_typed_prop(prop_info, property_val, value, &garbage, zobj EXECUTE_DATA_CC); goto free_and_exit_assign_obj; } else { fast_assign_obj: @@ -87995,7 +88015,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_OPCODE_HANDLER_CCONV ZEND_ASSIGN_OBJ_SPEC_VA property_val = OBJ_PROP(zobj, prop_offset); if (Z_TYPE_P(property_val) != IS_UNDEF) { if (prop_info != NULL) { - value = zend_assign_to_typed_prop(prop_info, property_val, value, &garbage EXECUTE_DATA_CC); + value = zend_assign_to_typed_prop(prop_info, property_val, value, &garbage, zobj EXECUTE_DATA_CC); goto free_and_exit_assign_obj; } else { fast_assign_obj: @@ -88150,7 +88170,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_OPCODE_HANDLER_CCONV ZEND_ASSIGN_OBJ_SPEC_VA property_val = OBJ_PROP(zobj, prop_offset); if (Z_TYPE_P(property_val) != IS_UNDEF) { if (prop_info != NULL) { - value = zend_assign_to_typed_prop(prop_info, property_val, value, &garbage EXECUTE_DATA_CC); + value = zend_assign_to_typed_prop(prop_info, property_val, value, &garbage, zobj EXECUTE_DATA_CC); goto free_and_exit_assign_obj; } else { fast_assign_obj: @@ -90512,7 +90532,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_OPCODE_HANDLER_CCONV ZEND_ASSIGN_OBJ_SPEC_UN property_val = OBJ_PROP(zobj, prop_offset); if (Z_TYPE_P(property_val) != IS_UNDEF) { if (prop_info != NULL) { - value = zend_assign_to_typed_prop(prop_info, property_val, value, &garbage EXECUTE_DATA_CC); + value = zend_assign_to_typed_prop(prop_info, property_val, value, &garbage, zobj EXECUTE_DATA_CC); goto free_and_exit_assign_obj; } else { fast_assign_obj: @@ -90670,7 +90690,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_OPCODE_HANDLER_CCONV ZEND_ASSIGN_OBJ_SPEC_UN property_val = OBJ_PROP(zobj, prop_offset); if (Z_TYPE_P(property_val) != IS_UNDEF) { if (prop_info != NULL) { - value = zend_assign_to_typed_prop(prop_info, property_val, value, &garbage EXECUTE_DATA_CC); + value = zend_assign_to_typed_prop(prop_info, property_val, value, &garbage, zobj EXECUTE_DATA_CC); goto free_and_exit_assign_obj; } else { fast_assign_obj: @@ -90826,7 +90846,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_OPCODE_HANDLER_CCONV ZEND_ASSIGN_OBJ_SPEC_UN property_val = OBJ_PROP(zobj, prop_offset); if (Z_TYPE_P(property_val) != IS_UNDEF) { if (prop_info != NULL) { - value = zend_assign_to_typed_prop(prop_info, property_val, value, &garbage EXECUTE_DATA_CC); + value = zend_assign_to_typed_prop(prop_info, property_val, value, &garbage, zobj EXECUTE_DATA_CC); goto free_and_exit_assign_obj; } else { fast_assign_obj: @@ -90982,7 +91002,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_OPCODE_HANDLER_CCONV ZEND_ASSIGN_OBJ_SPEC_UN property_val = OBJ_PROP(zobj, prop_offset); if (Z_TYPE_P(property_val) != IS_UNDEF) { if (prop_info != NULL) { - value = zend_assign_to_typed_prop(prop_info, property_val, value, &garbage EXECUTE_DATA_CC); + value = zend_assign_to_typed_prop(prop_info, property_val, value, &garbage, zobj EXECUTE_DATA_CC); goto free_and_exit_assign_obj; } else { fast_assign_obj: @@ -92752,7 +92772,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_OPCODE_HANDLER_CCONV ZEND_ASSIGN_OBJ_SPEC_UN property_val = OBJ_PROP(zobj, prop_offset); if (Z_TYPE_P(property_val) != IS_UNDEF) { if (prop_info != NULL) { - value = zend_assign_to_typed_prop(prop_info, property_val, value, &garbage EXECUTE_DATA_CC); + value = zend_assign_to_typed_prop(prop_info, property_val, value, &garbage, zobj EXECUTE_DATA_CC); goto free_and_exit_assign_obj; } else { fast_assign_obj: @@ -92909,7 +92929,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_OPCODE_HANDLER_CCONV ZEND_ASSIGN_OBJ_SPEC_UN property_val = OBJ_PROP(zobj, prop_offset); if (Z_TYPE_P(property_val) != IS_UNDEF) { if (prop_info != NULL) { - value = zend_assign_to_typed_prop(prop_info, property_val, value, &garbage EXECUTE_DATA_CC); + value = zend_assign_to_typed_prop(prop_info, property_val, value, &garbage, zobj EXECUTE_DATA_CC); goto free_and_exit_assign_obj; } else { fast_assign_obj: @@ -93064,7 +93084,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_OPCODE_HANDLER_CCONV ZEND_ASSIGN_OBJ_SPEC_UN property_val = OBJ_PROP(zobj, prop_offset); if (Z_TYPE_P(property_val) != IS_UNDEF) { if (prop_info != NULL) { - value = zend_assign_to_typed_prop(prop_info, property_val, value, &garbage EXECUTE_DATA_CC); + value = zend_assign_to_typed_prop(prop_info, property_val, value, &garbage, zobj EXECUTE_DATA_CC); goto free_and_exit_assign_obj; } else { fast_assign_obj: @@ -93219,7 +93239,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_OPCODE_HANDLER_CCONV ZEND_ASSIGN_OBJ_SPEC_UN property_val = OBJ_PROP(zobj, prop_offset); if (Z_TYPE_P(property_val) != IS_UNDEF) { if (prop_info != NULL) { - value = zend_assign_to_typed_prop(prop_info, property_val, value, &garbage EXECUTE_DATA_CC); + value = zend_assign_to_typed_prop(prop_info, property_val, value, &garbage, zobj EXECUTE_DATA_CC); goto free_and_exit_assign_obj; } else { fast_assign_obj: @@ -95462,7 +95482,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_OPCODE_HANDLER_CCONV ZEND_ASSIGN_OBJ_SPEC_UN property_val = OBJ_PROP(zobj, prop_offset); if (Z_TYPE_P(property_val) != IS_UNDEF) { if (prop_info != NULL) { - value = zend_assign_to_typed_prop(prop_info, property_val, value, &garbage EXECUTE_DATA_CC); + value = zend_assign_to_typed_prop(prop_info, property_val, value, &garbage, zobj EXECUTE_DATA_CC); goto free_and_exit_assign_obj; } else { fast_assign_obj: @@ -95620,7 +95640,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_OPCODE_HANDLER_CCONV ZEND_ASSIGN_OBJ_SPEC_UN property_val = OBJ_PROP(zobj, prop_offset); if (Z_TYPE_P(property_val) != IS_UNDEF) { if (prop_info != NULL) { - value = zend_assign_to_typed_prop(prop_info, property_val, value, &garbage EXECUTE_DATA_CC); + value = zend_assign_to_typed_prop(prop_info, property_val, value, &garbage, zobj EXECUTE_DATA_CC); goto free_and_exit_assign_obj; } else { fast_assign_obj: @@ -95776,7 +95796,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_OPCODE_HANDLER_CCONV ZEND_ASSIGN_OBJ_SPEC_UN property_val = OBJ_PROP(zobj, prop_offset); if (Z_TYPE_P(property_val) != IS_UNDEF) { if (prop_info != NULL) { - value = zend_assign_to_typed_prop(prop_info, property_val, value, &garbage EXECUTE_DATA_CC); + value = zend_assign_to_typed_prop(prop_info, property_val, value, &garbage, zobj EXECUTE_DATA_CC); goto free_and_exit_assign_obj; } else { fast_assign_obj: @@ -95932,7 +95952,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_OPCODE_HANDLER_CCONV ZEND_ASSIGN_OBJ_SPEC_UN property_val = OBJ_PROP(zobj, prop_offset); if (Z_TYPE_P(property_val) != IS_UNDEF) { if (prop_info != NULL) { - value = zend_assign_to_typed_prop(prop_info, property_val, value, &garbage EXECUTE_DATA_CC); + value = zend_assign_to_typed_prop(prop_info, property_val, value, &garbage, zobj EXECUTE_DATA_CC); goto free_and_exit_assign_obj; } else { fast_assign_obj: @@ -99959,7 +99979,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_OPCODE_HANDLER_CCONV ZEND_ASSIGN_OBJ_SPEC_CV property_val = OBJ_PROP(zobj, prop_offset); if (Z_TYPE_P(property_val) != IS_UNDEF) { if (prop_info != NULL) { - value = zend_assign_to_typed_prop(prop_info, property_val, value, &garbage EXECUTE_DATA_CC); + value = zend_assign_to_typed_prop(prop_info, property_val, value, &garbage, zobj EXECUTE_DATA_CC); goto free_and_exit_assign_obj; } else { fast_assign_obj: @@ -100117,7 +100137,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_OPCODE_HANDLER_CCONV ZEND_ASSIGN_OBJ_SPEC_CV property_val = OBJ_PROP(zobj, prop_offset); if (Z_TYPE_P(property_val) != IS_UNDEF) { if (prop_info != NULL) { - value = zend_assign_to_typed_prop(prop_info, property_val, value, &garbage EXECUTE_DATA_CC); + value = zend_assign_to_typed_prop(prop_info, property_val, value, &garbage, zobj EXECUTE_DATA_CC); goto free_and_exit_assign_obj; } else { fast_assign_obj: @@ -100273,7 +100293,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_OPCODE_HANDLER_CCONV ZEND_ASSIGN_OBJ_SPEC_CV property_val = OBJ_PROP(zobj, prop_offset); if (Z_TYPE_P(property_val) != IS_UNDEF) { if (prop_info != NULL) { - value = zend_assign_to_typed_prop(prop_info, property_val, value, &garbage EXECUTE_DATA_CC); + value = zend_assign_to_typed_prop(prop_info, property_val, value, &garbage, zobj EXECUTE_DATA_CC); goto free_and_exit_assign_obj; } else { fast_assign_obj: @@ -100429,7 +100449,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_OPCODE_HANDLER_CCONV ZEND_ASSIGN_OBJ_SPEC_CV property_val = OBJ_PROP(zobj, prop_offset); if (Z_TYPE_P(property_val) != IS_UNDEF) { if (prop_info != NULL) { - value = zend_assign_to_typed_prop(prop_info, property_val, value, &garbage EXECUTE_DATA_CC); + value = zend_assign_to_typed_prop(prop_info, property_val, value, &garbage, zobj EXECUTE_DATA_CC); goto free_and_exit_assign_obj; } else { fast_assign_obj: @@ -104035,7 +104055,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_OPCODE_HANDLER_CCONV ZEND_ASSIGN_OBJ_SPEC_CV property_val = OBJ_PROP(zobj, prop_offset); if (Z_TYPE_P(property_val) != IS_UNDEF) { if (prop_info != NULL) { - value = zend_assign_to_typed_prop(prop_info, property_val, value, &garbage EXECUTE_DATA_CC); + value = zend_assign_to_typed_prop(prop_info, property_val, value, &garbage, zobj EXECUTE_DATA_CC); goto free_and_exit_assign_obj; } else { fast_assign_obj: @@ -104192,7 +104212,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_OPCODE_HANDLER_CCONV ZEND_ASSIGN_OBJ_SPEC_CV property_val = OBJ_PROP(zobj, prop_offset); if (Z_TYPE_P(property_val) != IS_UNDEF) { if (prop_info != NULL) { - value = zend_assign_to_typed_prop(prop_info, property_val, value, &garbage EXECUTE_DATA_CC); + value = zend_assign_to_typed_prop(prop_info, property_val, value, &garbage, zobj EXECUTE_DATA_CC); goto free_and_exit_assign_obj; } else { fast_assign_obj: @@ -104347,7 +104367,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_OPCODE_HANDLER_CCONV ZEND_ASSIGN_OBJ_SPEC_CV property_val = OBJ_PROP(zobj, prop_offset); if (Z_TYPE_P(property_val) != IS_UNDEF) { if (prop_info != NULL) { - value = zend_assign_to_typed_prop(prop_info, property_val, value, &garbage EXECUTE_DATA_CC); + value = zend_assign_to_typed_prop(prop_info, property_val, value, &garbage, zobj EXECUTE_DATA_CC); goto free_and_exit_assign_obj; } else { fast_assign_obj: @@ -104502,7 +104522,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_OPCODE_HANDLER_CCONV ZEND_ASSIGN_OBJ_SPEC_CV property_val = OBJ_PROP(zobj, prop_offset); if (Z_TYPE_P(property_val) != IS_UNDEF) { if (prop_info != NULL) { - value = zend_assign_to_typed_prop(prop_info, property_val, value, &garbage EXECUTE_DATA_CC); + value = zend_assign_to_typed_prop(prop_info, property_val, value, &garbage, zobj EXECUTE_DATA_CC); goto free_and_exit_assign_obj; } else { fast_assign_obj: @@ -109603,7 +109623,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_OPCODE_HANDLER_CCONV ZEND_ASSIGN_OBJ_SPEC_CV property_val = OBJ_PROP(zobj, prop_offset); if (Z_TYPE_P(property_val) != IS_UNDEF) { if (prop_info != NULL) { - value = zend_assign_to_typed_prop(prop_info, property_val, value, &garbage EXECUTE_DATA_CC); + value = zend_assign_to_typed_prop(prop_info, property_val, value, &garbage, zobj EXECUTE_DATA_CC); goto free_and_exit_assign_obj; } else { fast_assign_obj: @@ -109761,7 +109781,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_OPCODE_HANDLER_CCONV ZEND_ASSIGN_OBJ_SPEC_CV property_val = OBJ_PROP(zobj, prop_offset); if (Z_TYPE_P(property_val) != IS_UNDEF) { if (prop_info != NULL) { - value = zend_assign_to_typed_prop(prop_info, property_val, value, &garbage EXECUTE_DATA_CC); + value = zend_assign_to_typed_prop(prop_info, property_val, value, &garbage, zobj EXECUTE_DATA_CC); goto free_and_exit_assign_obj; } else { fast_assign_obj: @@ -109917,7 +109937,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_OPCODE_HANDLER_CCONV ZEND_ASSIGN_OBJ_SPEC_CV property_val = OBJ_PROP(zobj, prop_offset); if (Z_TYPE_P(property_val) != IS_UNDEF) { if (prop_info != NULL) { - value = zend_assign_to_typed_prop(prop_info, property_val, value, &garbage EXECUTE_DATA_CC); + value = zend_assign_to_typed_prop(prop_info, property_val, value, &garbage, zobj EXECUTE_DATA_CC); goto free_and_exit_assign_obj; } else { fast_assign_obj: @@ -110073,7 +110093,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_OPCODE_HANDLER_CCONV ZEND_ASSIGN_OBJ_SPEC_CV property_val = OBJ_PROP(zobj, prop_offset); if (Z_TYPE_P(property_val) != IS_UNDEF) { if (prop_info != NULL) { - value = zend_assign_to_typed_prop(prop_info, property_val, value, &garbage EXECUTE_DATA_CC); + value = zend_assign_to_typed_prop(prop_info, property_val, value, &garbage, zobj EXECUTE_DATA_CC); goto free_and_exit_assign_obj; } else { fast_assign_obj: @@ -116334,7 +116354,12 @@ ZEND_API void execute_ex(zend_execute_data *ex) call_info = EX_CALL_INFO(); #endif if (UNEXPECTED(call_info & ZEND_CALL_RELEASE_THIS)) { - OBJ_RELEASE(Z_OBJ(execute_data->This)); + zend_object *obj = Z_OBJ(execute_data->This); + /* Mark that a constructor has completed on this object */ + if (EX(func)->common.fn_flags & ZEND_ACC_CTOR) { + obj->extra_flags |= IS_OBJ_CTOR_CALLED; + } + OBJ_RELEASE(obj); } else if (UNEXPECTED(call_info & ZEND_CALL_CLOSURE)) { OBJ_RELEASE(ZEND_CLOSURE_OBJECT(EX(func))); } @@ -116368,7 +116393,12 @@ ZEND_API void execute_ex(zend_execute_data *ex) zend_vm_stack_free_extra_args_ex(call_info, execute_data); if (UNEXPECTED(call_info & ZEND_CALL_RELEASE_THIS)) { - OBJ_RELEASE(Z_OBJ(execute_data->This)); + zend_object *obj = Z_OBJ(execute_data->This); + /* Mark that a constructor has completed on this object */ + if (EX(func)->common.fn_flags & ZEND_ACC_CTOR) { + obj->extra_flags |= IS_OBJ_CTOR_CALLED; + } + OBJ_RELEASE(obj); } else if (UNEXPECTED(call_info & ZEND_CALL_CLOSURE)) { OBJ_RELEASE(ZEND_CLOSURE_OBJECT(EX(func))); } diff --git a/ext/opcache/jit/zend_jit_helpers.c b/ext/opcache/jit/zend_jit_helpers.c index 07f1b61c6b520..2339fe0f278f1 100644 --- a/ext/opcache/jit/zend_jit_helpers.c +++ b/ext/opcache/jit/zend_jit_helpers.c @@ -2803,12 +2803,15 @@ static void ZEND_FASTCALL zend_jit_assign_obj_helper(zend_object *zobj, zend_str } } -static zend_always_inline bool verify_readonly_and_avis(zval *property_val, zend_property_info *info, bool indirect) +static zend_always_inline bool verify_readonly_and_avis(zval *property_val, zend_property_info *info, bool indirect, zend_object *zobj) { if (UNEXPECTED(info->flags & (ZEND_ACC_READONLY|ZEND_ACC_PPP_SET_MASK))) { - if ((info->flags & ZEND_ACC_READONLY) && !(Z_PROP_FLAG_P(property_val) & IS_PROP_REINITABLE)) { - zend_readonly_property_modification_error(info); - return false; + if (info->flags & ZEND_ACC_READONLY) { + ZEND_ASSERT(zobj != NULL); /* CPP_REINITABLE only applies to instance properties */ + if (!zend_is_readonly_property_modifiable(property_val, info->ce, zobj)) { + zend_readonly_property_modification_error(info); + return false; + } } if ((info->flags & ZEND_ACC_PPP_SET_MASK) && !zend_asymmetric_property_has_set_access(info)) { const char *operation = indirect ? "indirectly modify" : "modify"; @@ -2819,7 +2822,7 @@ static zend_always_inline bool verify_readonly_and_avis(zval *property_val, zend return true; } -static void ZEND_FASTCALL zend_jit_assign_to_typed_prop(zval *property_val, zend_property_info *info, zval *value, zval *result) +static void ZEND_FASTCALL zend_jit_assign_to_typed_prop(zval *property_val, zend_property_info *info, zval *value, zval *result, zend_object *zobj) { zend_execute_data *execute_data = EG(current_execute_data); zend_refcounted *garbage = NULL; @@ -2832,7 +2835,7 @@ static void ZEND_FASTCALL zend_jit_assign_to_typed_prop(zval *property_val, zend value = &EG(uninitialized_zval); } - if (UNEXPECTED(!verify_readonly_and_avis(property_val, info, false))) { + if (UNEXPECTED(!verify_readonly_and_avis(property_val, info, false, zobj))) { if (result) { ZVAL_UNDEF(result); } @@ -2850,7 +2853,7 @@ static void ZEND_FASTCALL zend_jit_assign_to_typed_prop(zval *property_val, zend return; } - Z_PROP_FLAG_P(property_val) &= ~IS_PROP_REINITABLE; + Z_PROP_FLAG_P(property_val) &= ~(IS_PROP_REINITABLE|IS_PROP_CPP_REINITABLE); value = zend_assign_to_variable_ex(property_val, &tmp, IS_TMP_VAR, EX_USES_STRICT_TYPES(), &garbage); if (result) { @@ -2888,12 +2891,12 @@ static zend_never_inline void _zend_jit_assign_op_overloaded_property(zend_objec OBJ_RELEASE(object); } -static void ZEND_FASTCALL zend_jit_assign_op_to_typed_prop(zval *zptr, zend_property_info *prop_info, zval *value, binary_op_type binary_op) +static void ZEND_FASTCALL zend_jit_assign_op_to_typed_prop(zval *zptr, zend_property_info *prop_info, zval *value, binary_op_type binary_op, zend_object *zobj) { zend_execute_data *execute_data = EG(current_execute_data); zval z_copy; - if (UNEXPECTED(!verify_readonly_and_avis(zptr, prop_info, true))) { + if (UNEXPECTED(!verify_readonly_and_avis(zptr, prop_info, true, zobj))) { return; } @@ -2907,7 +2910,7 @@ static void ZEND_FASTCALL zend_jit_assign_op_to_typed_prop(zval *zptr, zend_prop binary_op(&z_copy, zptr, value); if (EXPECTED(zend_verify_property_type(prop_info, &z_copy, EX_USES_STRICT_TYPES()))) { - Z_PROP_FLAG_P(zptr) &= ~IS_PROP_REINITABLE; + Z_PROP_FLAG_P(zptr) &= ~(IS_PROP_REINITABLE|IS_PROP_CPP_REINITABLE); zval_ptr_dtor(zptr); ZVAL_COPY_VALUE(zptr, &z_copy); } else { @@ -2946,7 +2949,7 @@ static void ZEND_FASTCALL zend_jit_assign_obj_op_helper(zend_object *zobj, zend_ //??? } if (prop_info) { /* special case for typed properties */ - zend_jit_assign_op_to_typed_prop(zptr, prop_info, value, binary_op); + zend_jit_assign_op_to_typed_prop(zptr, prop_info, value, binary_op, zobj); } else { binary_op(zptr, zptr, value); } @@ -2983,11 +2986,11 @@ static ZEND_COLD zend_long _zend_jit_throw_dec_prop_error(zend_property_info *pr return ZEND_LONG_MIN; } -static void ZEND_FASTCALL zend_jit_inc_typed_prop(zval *var_ptr, zend_property_info *prop_info) +static void ZEND_FASTCALL zend_jit_inc_typed_prop(zval *var_ptr, zend_property_info *prop_info, zend_object *zobj) { ZEND_ASSERT(Z_TYPE_P(var_ptr) != IS_UNDEF); - if (UNEXPECTED(!verify_readonly_and_avis(var_ptr, prop_info, true))) { + if (UNEXPECTED(!verify_readonly_and_avis(var_ptr, prop_info, true, zobj))) { return; } @@ -3004,22 +3007,22 @@ static void ZEND_FASTCALL zend_jit_inc_typed_prop(zval *var_ptr, zend_property_i zend_long val = _zend_jit_throw_inc_prop_error(prop_info); ZVAL_LONG(var_ptr, val); } else { - Z_PROP_FLAG_P(var_ptr) &= ~IS_PROP_REINITABLE; + Z_PROP_FLAG_P(var_ptr) &= ~(IS_PROP_REINITABLE|IS_PROP_CPP_REINITABLE); } } else if (UNEXPECTED(!zend_verify_property_type(prop_info, var_ptr, EX_USES_STRICT_TYPES()))) { zval_ptr_dtor(var_ptr); ZVAL_COPY_VALUE(var_ptr, &tmp); } else { - Z_PROP_FLAG_P(var_ptr) &= ~IS_PROP_REINITABLE; + Z_PROP_FLAG_P(var_ptr) &= ~(IS_PROP_REINITABLE|IS_PROP_CPP_REINITABLE); zval_ptr_dtor(&tmp); } } -static void ZEND_FASTCALL zend_jit_dec_typed_prop(zval *var_ptr, zend_property_info *prop_info) +static void ZEND_FASTCALL zend_jit_dec_typed_prop(zval *var_ptr, zend_property_info *prop_info, zend_object *zobj) { ZEND_ASSERT(Z_TYPE_P(var_ptr) != IS_UNDEF); - if (UNEXPECTED(!verify_readonly_and_avis(var_ptr, prop_info, true))) { + if (UNEXPECTED(!verify_readonly_and_avis(var_ptr, prop_info, true, zobj))) { return; } @@ -3036,36 +3039,36 @@ static void ZEND_FASTCALL zend_jit_dec_typed_prop(zval *var_ptr, zend_property_i zend_long val = _zend_jit_throw_dec_prop_error(prop_info); ZVAL_LONG(var_ptr, val); } else { - Z_PROP_FLAG_P(var_ptr) &= ~IS_PROP_REINITABLE; + Z_PROP_FLAG_P(var_ptr) &= ~(IS_PROP_REINITABLE|IS_PROP_CPP_REINITABLE); } } else if (UNEXPECTED(!zend_verify_property_type(prop_info, var_ptr, EX_USES_STRICT_TYPES()))) { zval_ptr_dtor(var_ptr); ZVAL_COPY_VALUE(var_ptr, &tmp); } else { - Z_PROP_FLAG_P(var_ptr) &= ~IS_PROP_REINITABLE; + Z_PROP_FLAG_P(var_ptr) &= ~(IS_PROP_REINITABLE|IS_PROP_CPP_REINITABLE); zval_ptr_dtor(&tmp); } } -static void ZEND_FASTCALL zend_jit_pre_inc_typed_prop(zval *var_ptr, zend_property_info *prop_info, zval *result) +static void ZEND_FASTCALL zend_jit_pre_inc_typed_prop(zval *var_ptr, zend_property_info *prop_info, zval *result, zend_object *zobj) { ZVAL_DEREF(var_ptr); - zend_jit_inc_typed_prop(var_ptr, prop_info); + zend_jit_inc_typed_prop(var_ptr, prop_info, zobj); ZVAL_COPY(result, var_ptr); } -static void ZEND_FASTCALL zend_jit_pre_dec_typed_prop(zval *var_ptr, zend_property_info *prop_info, zval *result) +static void ZEND_FASTCALL zend_jit_pre_dec_typed_prop(zval *var_ptr, zend_property_info *prop_info, zval *result, zend_object *zobj) { ZVAL_DEREF(var_ptr); - zend_jit_dec_typed_prop(var_ptr, prop_info); + zend_jit_dec_typed_prop(var_ptr, prop_info, zobj); ZVAL_COPY(result, var_ptr); } -static void ZEND_FASTCALL zend_jit_post_inc_typed_prop(zval *var_ptr, zend_property_info *prop_info, zval *result) +static void ZEND_FASTCALL zend_jit_post_inc_typed_prop(zval *var_ptr, zend_property_info *prop_info, zval *result, zend_object *zobj) { ZEND_ASSERT(Z_TYPE_P(var_ptr) != IS_UNDEF); - if (UNEXPECTED(!verify_readonly_and_avis(var_ptr, prop_info, true))) { + if (UNEXPECTED(!verify_readonly_and_avis(var_ptr, prop_info, true, zobj))) { if (result) { ZVAL_UNDEF(result); } @@ -3084,22 +3087,22 @@ static void ZEND_FASTCALL zend_jit_post_inc_typed_prop(zval *var_ptr, zend_prope zend_long val = _zend_jit_throw_inc_prop_error(prop_info); ZVAL_LONG(var_ptr, val); } else { - Z_PROP_FLAG_P(var_ptr) &= ~IS_PROP_REINITABLE; + Z_PROP_FLAG_P(var_ptr) &= ~(IS_PROP_REINITABLE|IS_PROP_CPP_REINITABLE); } } else if (UNEXPECTED(!zend_verify_property_type(prop_info, var_ptr, EX_USES_STRICT_TYPES()))) { zval_ptr_dtor(var_ptr); ZVAL_COPY_VALUE(var_ptr, result); ZVAL_UNDEF(result); } else { - Z_PROP_FLAG_P(var_ptr) &= ~IS_PROP_REINITABLE; + Z_PROP_FLAG_P(var_ptr) &= ~(IS_PROP_REINITABLE|IS_PROP_CPP_REINITABLE); } } -static void ZEND_FASTCALL zend_jit_post_dec_typed_prop(zval *var_ptr, zend_property_info *prop_info, zval *result) +static void ZEND_FASTCALL zend_jit_post_dec_typed_prop(zval *var_ptr, zend_property_info *prop_info, zval *result, zend_object *zobj) { ZEND_ASSERT(Z_TYPE_P(var_ptr) != IS_UNDEF); - if (UNEXPECTED(!verify_readonly_and_avis(var_ptr, prop_info, true))) { + if (UNEXPECTED(!verify_readonly_and_avis(var_ptr, prop_info, true, zobj))) { if (result) { ZVAL_UNDEF(result); } @@ -3118,14 +3121,14 @@ static void ZEND_FASTCALL zend_jit_post_dec_typed_prop(zval *var_ptr, zend_prope zend_long val = _zend_jit_throw_dec_prop_error(prop_info); ZVAL_LONG(var_ptr, val); } else { - Z_PROP_FLAG_P(var_ptr) &= ~IS_PROP_REINITABLE; + Z_PROP_FLAG_P(var_ptr) &= ~(IS_PROP_REINITABLE|IS_PROP_CPP_REINITABLE); } } else if (UNEXPECTED(!zend_verify_property_type(prop_info, var_ptr, EX_USES_STRICT_TYPES()))) { zval_ptr_dtor(var_ptr); ZVAL_COPY_VALUE(var_ptr, result); ZVAL_UNDEF(result); } else { - Z_PROP_FLAG_P(var_ptr) &= ~IS_PROP_REINITABLE; + Z_PROP_FLAG_P(var_ptr) &= ~(IS_PROP_REINITABLE|IS_PROP_CPP_REINITABLE); } } @@ -3160,7 +3163,7 @@ static void ZEND_FASTCALL zend_jit_pre_inc_obj_helper(zend_object *zobj, zend_st } if (prop_info) { - zend_jit_inc_typed_prop(prop, prop_info); + zend_jit_inc_typed_prop(prop, prop_info, zobj); } else { increment_function(prop); } @@ -3230,7 +3233,7 @@ static void ZEND_FASTCALL zend_jit_pre_dec_obj_helper(zend_object *zobj, zend_st } if (prop_info) { - zend_jit_dec_typed_prop(prop, prop_info); + zend_jit_dec_typed_prop(prop, prop_info, zobj); } else { decrement_function(prop); } @@ -3298,7 +3301,7 @@ static void ZEND_FASTCALL zend_jit_post_inc_obj_helper(zend_object *zobj, zend_s } if (prop_info) { - zend_jit_post_inc_typed_prop(prop, prop_info, result); + zend_jit_post_inc_typed_prop(prop, prop_info, result, zobj); } else { ZVAL_COPY(result, prop); increment_function(prop); @@ -3359,7 +3362,7 @@ static void ZEND_FASTCALL zend_jit_post_dec_obj_helper(zend_object *zobj, zend_s } if (prop_info) { - zend_jit_post_dec_typed_prop(prop, prop_info, result); + zend_jit_post_dec_typed_prop(prop, prop_info, result, zobj); } else { ZVAL_COPY(result, prop); decrement_function(prop); diff --git a/ext/opcache/jit/zend_jit_ir.c b/ext/opcache/jit/zend_jit_ir.c index ace1206682042..067048a94aed9 100644 --- a/ext/opcache/jit/zend_jit_ir.c +++ b/ext/opcache/jit/zend_jit_ir.c @@ -14917,11 +14917,12 @@ static int zend_jit_assign_obj(zend_jit_ctx *jit, } // JIT: value = zend_assign_to_typed_prop(prop_info, property_val, value EXECUTE_DATA_CC); jit_SET_EX_OPLINE(jit, opline); - ir_CALL_4(IR_VOID, ir_CONST_FC_FUNC(zend_jit_assign_to_typed_prop), + ir_CALL_5(IR_VOID, ir_CONST_FC_FUNC(zend_jit_assign_to_typed_prop), prop_ref, prop_info_ref, arg3, - arg4); + arg4, + obj_ref); if ((opline+1)->op1_type == IS_CONST) { // TODO: ??? @@ -14989,11 +14990,12 @@ static int zend_jit_assign_obj(zend_jit_ctx *jit, } else { arg4 = jit_ZVAL_ADDR(jit, res_addr); } - ir_CALL_4(IR_VOID, ir_CONST_FC_FUNC(zend_jit_assign_to_typed_prop), + ir_CALL_5(IR_VOID, ir_CONST_FC_FUNC(zend_jit_assign_to_typed_prop), prop_ref, ref, arg3, - arg4); + arg4, + obj_ref); ir_END_list(end_inputs); } @@ -15331,11 +15333,12 @@ static int zend_jit_assign_obj_op(zend_jit_ctx *jit, ref = ir_LOAD_A(ir_ADD_OFFSET(ref, prop_info_offset)); } - ir_CALL_4(IR_VOID, ir_CONST_FC_FUNC(zend_jit_assign_op_to_typed_prop), + ir_CALL_5(IR_VOID, ir_CONST_FC_FUNC(zend_jit_assign_op_to_typed_prop), prop_ref, ref, arg2, - ir_CONST_FC_FUNC(binary_op)); + ir_CONST_FC_FUNC(binary_op), + obj_ref); ir_END_list(end_inputs); } @@ -15735,7 +15738,7 @@ static int zend_jit_incdec_obj(zend_jit_ctx *jit, ZEND_UNREACHABLE(); } - ir_CALL_2(IR_VOID, ir_CONST_FC_FUNC(func), prop_ref, ref); + ir_CALL_3(IR_VOID, ir_CONST_FC_FUNC(func), prop_ref, ref, obj_ref); } else { switch (opline->opcode) { case ZEND_PRE_INC_OBJ: @@ -15753,10 +15756,11 @@ static int zend_jit_incdec_obj(zend_jit_ctx *jit, default: ZEND_UNREACHABLE(); } - ir_CALL_3(IR_VOID, ir_CONST_FC_FUNC(func), + ir_CALL_4(IR_VOID, ir_CONST_FC_FUNC(func), prop_ref, ref, - jit_ZVAL_ADDR(jit, res_addr)); + jit_ZVAL_ADDR(jit, res_addr), + obj_ref); } ir_END_list(end_inputs); }