Skip to content

Commit c10c4cd

Browse files
committed
Make it possible to reinitialize readonly properties after a type error
1 parent 0ee50b5 commit c10c4cd

File tree

3 files changed

+23
-21
lines changed

3 files changed

+23
-21
lines changed

Zend/tests/readonly_props/readonly_clone_success4.phpt

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,9 @@ Readonly property can be reset once during cloning even after a type error
44
<?php
55

66
class Foo {
7-
public readonly int $bar;
7+
public function __construct(
8+
public readonly int $bar
9+
) {}
810

911
public function __clone()
1012
{
@@ -18,7 +20,7 @@ class Foo {
1820
}
1921
}
2022

21-
$foo = new Foo();
23+
$foo = new Foo(1);
2224

2325
var_dump(clone $foo);
2426
var_dump(clone $foo);

Zend/zend_execute.c

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1009,23 +1009,24 @@ static zend_never_inline zval* zend_assign_to_typed_prop(zend_property_info *inf
10091009
{
10101010
zval tmp;
10111011

1012+
ZVAL_DEREF(value);
1013+
ZVAL_COPY(&tmp, value);
1014+
1015+
if (UNEXPECTED(!i_zend_verify_property_type(info, &tmp, EX_USES_STRICT_TYPES()))) {
1016+
zval_ptr_dtor(&tmp);
1017+
return &EG(uninitialized_zval);
1018+
}
1019+
10121020
if (UNEXPECTED(info->flags & ZEND_ACC_READONLY)) {
10131021
if (Z_PROP_FLAG_P(property_val) & IS_PROP_REINITABLE) {
10141022
Z_PROP_FLAG_P(property_val) &= ~IS_PROP_REINITABLE;
10151023
} else {
1024+
zval_ptr_dtor(&tmp);
10161025
zend_readonly_property_modification_error(info);
10171026
return &EG(uninitialized_zval);
10181027
}
10191028
}
10201029

1021-
ZVAL_DEREF(value);
1022-
ZVAL_COPY(&tmp, value);
1023-
1024-
if (UNEXPECTED(!i_zend_verify_property_type(info, &tmp, EX_USES_STRICT_TYPES()))) {
1025-
zval_ptr_dtor(&tmp);
1026-
return &EG(uninitialized_zval);
1027-
}
1028-
10291030
return zend_assign_to_variable(property_val, &tmp, IS_TMP_VAR, EX_USES_STRICT_TYPES());
10301031
}
10311032

Zend/zend_object_handlers.c

Lines changed: 10 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -812,17 +812,6 @@ ZEND_API zval *zend_std_write_property(zend_object *zobj, zend_string *name, zva
812812
Z_TRY_ADDREF_P(value);
813813

814814
if (UNEXPECTED(prop_info)) {
815-
if (UNEXPECTED(prop_info->flags & ZEND_ACC_READONLY)) {
816-
if (Z_PROP_FLAG_P(variable_ptr) & IS_PROP_REINITABLE) {
817-
Z_PROP_FLAG_P(variable_ptr) &= ~IS_PROP_REINITABLE;
818-
} else {
819-
Z_TRY_DELREF_P(value);
820-
zend_readonly_property_modification_error(prop_info);
821-
variable_ptr = &EG(error_zval);
822-
goto exit;
823-
}
824-
}
825-
826815
ZVAL_COPY_VALUE(&tmp, value);
827816
// Increase refcount to prevent object from being released in __toString()
828817
GC_ADDREF(zobj);
@@ -839,6 +828,16 @@ ZEND_API zval *zend_std_write_property(zend_object *zobj, zend_string *name, zva
839828
variable_ptr = &EG(error_zval);
840829
goto exit;
841830
}
831+
if (UNEXPECTED(prop_info->flags & ZEND_ACC_READONLY)) {
832+
if (Z_PROP_FLAG_P(variable_ptr) & IS_PROP_REINITABLE) {
833+
Z_PROP_FLAG_P(variable_ptr) &= ~IS_PROP_REINITABLE;
834+
} else {
835+
Z_TRY_DELREF_P(value);
836+
zend_readonly_property_modification_error(prop_info);
837+
variable_ptr = &EG(error_zval);
838+
goto exit;
839+
}
840+
}
842841
value = &tmp;
843842
}
844843

0 commit comments

Comments
 (0)