Skip to content

Commit 6b37b86

Browse files
Handle promoted readonly reassignment in readonly failure paths
1 parent 6f8fcf1 commit 6b37b86

16 files changed

+351
-332
lines changed

Zend/Optimizer/compact_literals.c

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -514,15 +514,18 @@ void zend_optimizer_compact_literals(zend_op_array *op_array, zend_optimizer_ctx
514514
case ZEND_POST_INC_OBJ:
515515
case ZEND_POST_DEC_OBJ:
516516
if (opline->op2_type == IS_CONST) {
517+
uint32_t obj_flags = (opline->opcode == ZEND_ASSIGN_OBJ || opline->opcode == ZEND_ASSIGN_OBJ_REF)
518+
? ZEND_ASSIGN_OBJ_FLAGS
519+
: ZEND_FETCH_OBJ_FLAGS;
517520
// op2 property
518521
if (opline->op1_type == IS_UNUSED &&
519522
property_slot[opline->op2.constant] >= 0) {
520-
opline->extended_value = property_slot[opline->op2.constant] | (opline->extended_value & ZEND_FETCH_OBJ_FLAGS);
523+
opline->extended_value = property_slot[opline->op2.constant] | (opline->extended_value & obj_flags);
521524
} else {
522-
opline->extended_value = cache_size | (opline->extended_value & ZEND_FETCH_OBJ_FLAGS);
525+
opline->extended_value = cache_size | (opline->extended_value & obj_flags);
523526
cache_size += 3 * sizeof(void *);
524527
if (opline->op1_type == IS_UNUSED) {
525-
property_slot[opline->op2.constant] = opline->extended_value & ~ZEND_FETCH_OBJ_FLAGS;
528+
property_slot[opline->op2.constant] = opline->extended_value & ~obj_flags;
526529
}
527530
}
528531
}

Zend/tests/readonly_props/cpp_reassign_grandchild_redefine.phpt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,4 +36,4 @@ new D();
3636
?>
3737
--EXPECT--
3838
Error: Cannot modify readonly property D::$x
39-
string(2) "C2"
39+
string(2) "C2"

Zend/zend_API.c

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1744,7 +1744,7 @@ ZEND_API void object_properties_load(zend_object *object, const HashTable *prope
17441744
zval *slot = OBJ_PROP(object, property_info->offset);
17451745
if (UNEXPECTED((property_info->flags & ZEND_ACC_READONLY) && !Z_ISUNDEF_P(slot))) {
17461746
if (Z_PROP_FLAG_P(slot) & IS_PROP_REINITABLE) {
1747-
Z_PROP_FLAG_P(slot) &= ~(IS_PROP_REINITABLE | IS_PROP_CTOR_REINITABLE);
1747+
Z_PROP_FLAG_P(slot) &= ~IS_PROP_REINITABLE;
17481748
} else {
17491749
zend_readonly_property_modification_error(property_info);
17501750
return;
@@ -4422,9 +4422,6 @@ ZEND_API zend_property_info *zend_declare_typed_property(zend_class_entry *ce, z
44224422

44234423
if (access_type & ZEND_ACC_READONLY) {
44244424
ce->ce_flags |= ZEND_ACC_HAS_READONLY_PROPS;
4425-
if (access_type & ZEND_ACC_PROMOTED) {
4426-
ce->ce_flags |= ZEND_ACC_HAS_PROMOTED_READONLY_PROPS;
4427-
}
44284425
}
44294426
}
44304427

Zend/zend_compile.c

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8310,6 +8310,9 @@ static void zend_compile_params(zend_ast *ast, zend_ast *return_type_ast, uint32
83108310
zend_op *opline = zend_emit_op(NULL,
83118311
is_ref ? ZEND_ASSIGN_OBJ_REF : ZEND_ASSIGN_OBJ, NULL, &name_node);
83128312
opline->extended_value = zend_alloc_cache_slots(3);
8313+
if ((flags & ZEND_ACC_READONLY) != 0) {
8314+
opline->extended_value |= ZEND_ASSIGN_OBJ_PROMOTED_READONLY_INIT;
8315+
}
83138316
zend_emit_op_data(&value_node);
83148317
}
83158318
}

Zend/zend_compile.h

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -338,8 +338,6 @@ typedef struct _zend_oparray_context {
338338
/* loaded from file cache to process memory | | | */
339339
#define ZEND_ACC_FILE_CACHED (1 << 27) /* X | | | */
340340
/* | | | */
341-
#define ZEND_ACC_HAS_PROMOTED_READONLY_PROPS (1u << 31) /* X | | | */
342-
343341
/* Class cannot be serialized or unserialized | | | */
344342
#define ZEND_ACC_NOT_SERIALIZABLE (1 << 29) /* X | | | */
345343
/* | | | */
@@ -1099,6 +1097,9 @@ ZEND_API zend_string *zend_type_to_string(zend_type type);
10991097
#define ZEND_FETCH_DIM_WRITE 2
11001098
#define ZEND_FETCH_OBJ_FLAGS 3
11011099

1100+
#define ZEND_ASSIGN_OBJ_PROMOTED_READONLY_INIT (1u << 31)
1101+
#define ZEND_ASSIGN_OBJ_FLAGS (ZEND_FETCH_OBJ_FLAGS | ZEND_ASSIGN_OBJ_PROMOTED_READONLY_INIT)
1102+
11021103
/* Used to mark what kind of operation a writing FETCH_DIM is used in,
11031104
* to produce a more precise error on incorrect string offset use. */
11041105
#define ZEND_FETCH_DIM_REF 1

Zend/zend_execute.c

Lines changed: 11 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -1071,10 +1071,14 @@ ZEND_API bool zend_never_inline zend_verify_property_type(const zend_property_in
10711071
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)
10721072
{
10731073
zval tmp;
1074+
zend_readonly_write_kind readonly_write_kind = ZEND_READONLY_WRITE_FORBIDDEN;
10741075

10751076
if (UNEXPECTED(info->flags & (ZEND_ACC_READONLY|ZEND_ACC_PPP_SET_MASK))) {
1077+
if (info->flags & ZEND_ACC_READONLY) {
1078+
readonly_write_kind = zend_get_readonly_write_kind(property_val, info);
1079+
}
10761080
if ((info->flags & ZEND_ACC_READONLY)
1077-
&& (!zend_readonly_property_is_reinitable_for_context(property_val, info)
1081+
&& (readonly_write_kind == ZEND_READONLY_WRITE_FORBIDDEN
10781082
|| zend_is_foreign_cpp_overwrite(property_val, info))) {
10791083
zend_readonly_property_modification_error(info);
10801084
return &EG(uninitialized_zval);
@@ -1093,7 +1097,11 @@ static zend_never_inline zval* zend_assign_to_typed_prop(const zend_property_inf
10931097
return &EG(uninitialized_zval);
10941098
}
10951099

1096-
Z_PROP_FLAG_P(property_val) &= ~(IS_PROP_REINITABLE | IS_PROP_CTOR_REINITABLE);
1100+
if (readonly_write_kind == ZEND_READONLY_WRITE_REINITABLE) {
1101+
Z_PROP_FLAG_P(property_val) &= ~IS_PROP_REINITABLE;
1102+
} else if (readonly_write_kind == ZEND_READONLY_WRITE_CTOR_REASSIGNED) {
1103+
Z_PROP_FLAG_P(property_val) |= IS_PROP_CTOR_REASSIGNED;
1104+
}
10971105

10981106
return zend_assign_to_variable_ex(property_val, &tmp, IS_TMP_VAR, EX_USES_STRICT_TYPES(), garbage_ptr);
10991107
}
@@ -3656,7 +3664,7 @@ static zend_always_inline void zend_fetch_property_address(zval *result, zval *c
36563664
static zend_always_inline void zend_assign_to_property_reference(zval *container, uint32_t container_op_type, zval *prop_ptr, uint32_t prop_op_type, zval *value_ptr OPLINE_DC EXECUTE_DATA_DC)
36573665
{
36583666
zval variable, *variable_ptr = &variable;
3659-
void **cache_addr = (prop_op_type == IS_CONST) ? CACHE_ADDR(opline->extended_value & ~ZEND_RETURNS_FUNCTION) : NULL;
3667+
void **cache_addr = (prop_op_type == IS_CONST) ? CACHE_ADDR(opline->extended_value & ~(ZEND_RETURNS_FUNCTION | ZEND_ASSIGN_OBJ_PROMOTED_READONLY_INIT)) : NULL;
36603668
zend_refcounted *garbage = NULL;
36613669
zend_property_info *prop_info = NULL;
36623670

@@ -5899,53 +5907,6 @@ static zend_always_inline zend_execute_data *_zend_vm_stack_push_call_frame(uint
58995907
/* This callback disables optimization of "vm_stack_data" variable in VM */
59005908
ZEND_API void (ZEND_FASTCALL *zend_touch_vm_stack_data)(void *vm_stack_data) = NULL;
59015909

5902-
static zend_always_inline bool zend_has_more_derived_promoted_override(
5903-
const zend_class_entry *runtime_ce, const zend_class_entry *ctor_scope, zend_string *property_name)
5904-
{
5905-
for (const zend_class_entry *ce = runtime_ce; ce != NULL && ce != ctor_scope; ce = ce->parent) {
5906-
zend_property_info *prop_info = zend_hash_find_ptr(&ce->properties_info, property_name);
5907-
if (prop_info != NULL && (prop_info->flags & ZEND_ACC_PROMOTED)) {
5908-
return true;
5909-
}
5910-
}
5911-
return false;
5912-
}
5913-
5914-
/* Outlined slow path: clear IS_PROP_REINITABLE from promoted readonly properties
5915-
* of the exiting constructor's scope. Skips properties that a child class has
5916-
* redefined with its own CPP (the child owns that reassignment window). */
5917-
static zend_never_inline void zend_ctor_clear_promoted_readonly_reinitable_slow(zend_execute_data *ex)
5918-
{
5919-
zend_object *obj = Z_OBJ(ex->This);
5920-
zend_class_entry *ctor_scope = ex->func->common.scope;
5921-
zend_property_info *prop_info;
5922-
5923-
ZEND_HASH_MAP_FOREACH_PTR(&ctor_scope->properties_info, prop_info) {
5924-
if ((prop_info->flags & (ZEND_ACC_READONLY | ZEND_ACC_PROMOTED)) == (ZEND_ACC_READONLY | ZEND_ACC_PROMOTED)
5925-
&& IS_VALID_PROPERTY_OFFSET(prop_info->offset)) {
5926-
/* When the object is an instance of a descendant class, do not clear the
5927-
* window if a more-derived class owns the property through its own CPP,
5928-
* even if the runtime class itself redeclared it without CPP. */
5929-
if (obj->ce != ctor_scope
5930-
&& zend_has_more_derived_promoted_override(obj->ce, ctor_scope, prop_info->name)) {
5931-
continue;
5932-
}
5933-
Z_PROP_FLAG_P(OBJ_PROP(obj, prop_info->offset)) &= ~(IS_PROP_REINITABLE | IS_PROP_CTOR_REINITABLE);
5934-
}
5935-
} ZEND_HASH_FOREACH_END();
5936-
}
5937-
5938-
/* Clear IS_PROP_REINITABLE from all promoted readonly properties of the exiting
5939-
* constructor's scope. Called for both 'new Foo()' and 'parent::__construct()'. */
5940-
ZEND_API void ZEND_FASTCALL zend_ctor_clear_promoted_readonly_reinitable(zend_execute_data *ex, uint32_t call_info)
5941-
{
5942-
if ((call_info & ZEND_CALL_HAS_THIS)
5943-
&& (ex->func->common.fn_flags & ZEND_ACC_CTOR)
5944-
&& ZEND_CLASS_HAS_PROMOTED_READONLY_PROPS(ex->func->common.scope)) {
5945-
zend_ctor_clear_promoted_readonly_reinitable_slow(ex);
5946-
}
5947-
}
5948-
59495910
#include "zend_vm_execute.h"
59505911

59515912
ZEND_API zend_result zend_set_user_opcode_handler(zend_uchar opcode, user_opcode_handler_t handler)

Zend/zend_execute.h

Lines changed: 42 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -583,7 +583,6 @@ ZEND_API zend_result ZEND_FASTCALL zend_handle_undef_args(zend_execute_data *cal
583583

584584
#define ZEND_CLASS_HAS_TYPE_HINTS(ce) ((bool)(ce->ce_flags & ZEND_ACC_HAS_TYPE_HINTS))
585585
#define ZEND_CLASS_HAS_READONLY_PROPS(ce) ((bool)(ce->ce_flags & ZEND_ACC_HAS_READONLY_PROPS))
586-
#define ZEND_CLASS_HAS_PROMOTED_READONLY_PROPS(ce) ((bool)(ce->ce_flags & ZEND_ACC_HAS_PROMOTED_READONLY_PROPS))
587586

588587
static zend_always_inline bool zend_scope_is_derived_from(
589588
const zend_class_entry *scope, const zend_class_entry *ancestor)
@@ -650,19 +649,53 @@ static zend_always_inline bool zend_has_active_ctor_with_promoted_property(
650649
return false;
651650
}
652651

653-
static zend_always_inline bool zend_readonly_property_is_reinitable_for_context(
654-
const zval *property_val, const zend_property_info *prop_info)
652+
static zend_always_inline bool zend_is_promoted_readonly_ctor_init_assign(
653+
const zend_execute_data *ex, const zend_property_info *prop_info)
655654
{
656-
if (!(Z_PROP_FLAG_P(property_val) & IS_PROP_REINITABLE)) {
655+
if (ex == NULL
656+
|| ex->opline == NULL
657+
|| !((ex->opline->opcode == ZEND_ASSIGN_OBJ || ex->opline->opcode == ZEND_ASSIGN_OBJ_REF)
658+
&& (ex->opline->extended_value & ZEND_ASSIGN_OBJ_PROMOTED_READONLY_INIT))) {
657659
return false;
658660
}
659-
if (!(Z_PROP_FLAG_P(property_val) & IS_PROP_CTOR_REINITABLE)) {
660-
return true;
661+
if (!(ZEND_CALL_INFO(ex) & ZEND_CALL_HAS_THIS)) {
662+
return false;
663+
}
664+
return zend_has_active_ctor_with_promoted_property(ex, Z_OBJ(ex->This), prop_info->name);
665+
}
666+
667+
static zend_always_inline zend_object *zend_property_owner_from_slot(
668+
const zval *property_val, const zend_property_info *prop_info)
669+
{
670+
return (zend_object *) ((char *) property_val - prop_info->offset);
671+
}
672+
673+
typedef enum _zend_readonly_write_kind {
674+
ZEND_READONLY_WRITE_FORBIDDEN = 0, /* Write disallowed, or no special flag update needed */
675+
ZEND_READONLY_WRITE_REINITABLE, /* Clone reinit window: clear IS_PROP_REINITABLE after write */
676+
ZEND_READONLY_WRITE_CTOR_REASSIGNED, /* CPP ctor reassignment: set IS_PROP_CTOR_REASSIGNED after write */
677+
} zend_readonly_write_kind;
678+
679+
static zend_always_inline zend_readonly_write_kind zend_get_readonly_write_kind(
680+
const zval *property_val, const zend_property_info *prop_info)
681+
{
682+
if (Z_PROP_FLAG_P(property_val) & IS_PROP_REINITABLE) {
683+
return ZEND_READONLY_WRITE_REINITABLE;
684+
}
685+
if (Z_PROP_FLAG_P(property_val) & IS_PROP_CTOR_REASSIGNED) {
686+
return ZEND_READONLY_WRITE_FORBIDDEN;
661687
}
662688
zend_execute_data *ex = EG(current_execute_data);
663-
return ex
664-
&& (ZEND_CALL_INFO(ex) & ZEND_CALL_HAS_THIS)
665-
&& zend_has_active_ctor_with_promoted_property(ex, Z_OBJ(ex->This), prop_info->name);
689+
if (ex == NULL
690+
|| !(ZEND_CALL_INFO(ex) & ZEND_CALL_HAS_THIS)
691+
|| !zend_has_active_ctor_with_promoted_property(ex, Z_OBJ(ex->This), prop_info->name)
692+
|| zend_property_owner_from_slot(property_val, prop_info) != Z_OBJ(ex->This)
693+
|| (ex->opline != NULL
694+
&& (ex->opline->opcode == ZEND_ASSIGN_OBJ || ex->opline->opcode == ZEND_ASSIGN_OBJ_REF)
695+
&& (ex->opline->extended_value & ZEND_ASSIGN_OBJ_PROMOTED_READONLY_INIT))) {
696+
return ZEND_READONLY_WRITE_FORBIDDEN;
697+
}
698+
return ZEND_READONLY_WRITE_CTOR_REASSIGNED;
666699
}
667700

668701
/* Check if a foreign constructor is attempting a CPP initial assignment on an
@@ -684,7 +717,6 @@ static zend_always_inline bool zend_is_foreign_cpp_overwrite(
684717
return true;
685718
}
686719
if (!(prop_info->flags & ZEND_ACC_PROMOTED)
687-
&& (Z_PROP_FLAG_P(property_val) & IS_PROP_REINITABLE)
688720
&& zend_has_active_derived_ctor_with_promoted_property(ex, Z_OBJ(ex->This), prop_info)) {
689721
return true;
690722
}
@@ -697,7 +729,6 @@ ZEND_COLD void zend_verify_class_constant_type_error(const zend_class_constant *
697729
ZEND_API bool zend_verify_property_type(const zend_property_info *info, zval *property, bool strict);
698730
ZEND_COLD void zend_verify_property_type_error(const zend_property_info *info, const zval *property);
699731
ZEND_COLD void zend_magic_get_property_type_inconsistency_error(const zend_property_info *info, const zval *property);
700-
ZEND_API void ZEND_FASTCALL zend_ctor_clear_promoted_readonly_reinitable(zend_execute_data *ex, uint32_t call_info);
701732

702733
#define ZEND_REF_ADD_TYPE_SOURCE(ref, source) \
703734
zend_ref_add_type_source(&ZEND_REF_TYPE_SOURCES(ref), source)

Zend/zend_object_handlers.c

Lines changed: 14 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -1049,12 +1049,14 @@ ZEND_API zval *zend_std_write_property(zend_object *zobj, zend_string *name, zva
10491049
uintptr_t property_offset;
10501050
const zend_property_info *prop_info = NULL;
10511051
uint32_t *guard = NULL;
1052+
zend_readonly_write_kind readonly_write_kind = ZEND_READONLY_WRITE_FORBIDDEN;
10521053
ZEND_ASSERT(!Z_ISREF_P(value));
10531054

10541055
property_offset = zend_get_property_offset(zobj->ce, name, (zobj->ce->__set != NULL), cache_slot, &prop_info);
10551056

10561057
if (EXPECTED(IS_VALID_PROPERTY_OFFSET(property_offset))) {
10571058
try_again:
1059+
readonly_write_kind = ZEND_READONLY_WRITE_FORBIDDEN;
10581060
variable_ptr = OBJ_PROP(zobj, property_offset);
10591061

10601062
if (prop_info && UNEXPECTED(prop_info->flags & (ZEND_ACC_READONLY|ZEND_ACC_PPP_SET_MASK))) {
@@ -1066,9 +1068,12 @@ ZEND_API zval *zend_std_write_property(zend_object *zobj, zend_string *name, zva
10661068
error = (*guard) & IN_SET;
10671069
}
10681070
if (error) {
1071+
if ((prop_info->flags & ZEND_ACC_READONLY) && Z_TYPE_P(variable_ptr) != IS_UNDEF) {
1072+
readonly_write_kind = zend_get_readonly_write_kind(variable_ptr, prop_info);
1073+
}
10691074
if ((prop_info->flags & ZEND_ACC_READONLY)
10701075
&& Z_TYPE_P(variable_ptr) != IS_UNDEF
1071-
&& (!zend_readonly_property_is_reinitable_for_context(variable_ptr, prop_info)
1076+
&& (readonly_write_kind == ZEND_READONLY_WRITE_FORBIDDEN
10721077
|| zend_is_foreign_cpp_overwrite(variable_ptr, prop_info))) {
10731078
zend_readonly_property_modification_error(prop_info);
10741079
variable_ptr = &EG(error_zval);
@@ -1103,42 +1108,7 @@ ZEND_API zval *zend_std_write_property(zend_object *zobj, zend_string *name, zva
11031108
variable_ptr = &EG(error_zval);
11041109
goto exit;
11051110
}
1106-
/* For readonly properties initialized for the first time via CPP, set
1107-
* IS_PROP_REINITABLE to allow one reassignment in the constructor body.
1108-
* The flag is cleared by zend_leave_helper when the constructor exits.
1109-
*
1110-
* Classical case: the property is promoted in the declaring class and the
1111-
* executing constructor belongs to that class (scope == prop_info->ce).
1112-
*
1113-
* Extended case: a child class redeclared the property without CPP, so
1114-
* prop_info->ce is the child but the property isn't promoted there. CPP
1115-
* "ownership" still belongs to the ancestor whose constructor has CPP for
1116-
* this property name, so its body is allowed to reassign once. The clearing
1117-
* loop in zend_leave_helper iterates the exiting ctor's own promoted props,
1118-
* which share the same object slot, so cleanup happens automatically. */
1119-
bool reinitable = false;
1120-
if ((prop_info->flags & ZEND_ACC_READONLY)
1121-
&& (Z_PROP_FLAG_P(variable_ptr) & IS_PROP_UNINIT)
1122-
&& EG(current_execute_data)
1123-
&& (EG(current_execute_data)->func->common.fn_flags & ZEND_ACC_CTOR)) {
1124-
zend_class_entry *ctor_scope = EG(current_execute_data)->func->common.scope;
1125-
if (prop_info->flags & ZEND_ACC_PROMOTED) {
1126-
reinitable = (ctor_scope == prop_info->ce);
1127-
} else if (ctor_scope != prop_info->ce) {
1128-
/* Child redeclared without CPP: check if the executing ctor's class
1129-
* has a CPP declaration for this property name. */
1130-
zend_property_info *scope_prop = zend_hash_find_ptr(
1131-
&ctor_scope->properties_info, prop_info->name);
1132-
reinitable = scope_prop != NULL
1133-
&& (scope_prop->flags & (ZEND_ACC_READONLY|ZEND_ACC_PROMOTED))
1134-
== (ZEND_ACC_READONLY|ZEND_ACC_PROMOTED);
1135-
}
1136-
}
1137-
if (reinitable) {
1138-
Z_PROP_FLAG_P(variable_ptr) = IS_PROP_REINITABLE | IS_PROP_CTOR_REINITABLE;
1139-
} else {
1140-
Z_PROP_FLAG_P(variable_ptr) &= ~(IS_PROP_UNINIT|IS_PROP_REINITABLE|IS_PROP_CTOR_REINITABLE);
1141-
}
1111+
Z_PROP_FLAG_P(variable_ptr) &= ~(IS_PROP_UNINIT|IS_PROP_REINITABLE);
11421112
value = &tmp;
11431113
}
11441114

@@ -1148,6 +1118,12 @@ found:;
11481118
variable_ptr = zend_assign_to_variable_ex(
11491119
variable_ptr, value, IS_TMP_VAR, property_uses_strict_types(), &garbage);
11501120

1121+
if (readonly_write_kind == ZEND_READONLY_WRITE_REINITABLE) {
1122+
Z_PROP_FLAG_P(variable_ptr) &= ~IS_PROP_REINITABLE;
1123+
} else if (readonly_write_kind == ZEND_READONLY_WRITE_CTOR_REASSIGNED) {
1124+
Z_PROP_FLAG_P(variable_ptr) |= IS_PROP_CTOR_REASSIGNED;
1125+
}
1126+
11511127
if (garbage) {
11521128
if (GC_DELREF(garbage) == 0) {
11531129
zend_execute_data *execute_data = EG(current_execute_data);
@@ -1556,7 +1532,7 @@ ZEND_API void zend_std_unset_property(zend_object *zobj, zend_string *name, void
15561532
if (error) {
15571533
if ((prop_info->flags & ZEND_ACC_READONLY)
15581534
&& Z_TYPE_P(slot) != IS_UNDEF
1559-
&& !zend_readonly_property_is_reinitable_for_context(slot, prop_info)) {
1535+
&& !(Z_PROP_FLAG_P(slot) & IS_PROP_REINITABLE)) {
15601536
zend_readonly_property_unset_error(prop_info->ce, name);
15611537
return;
15621538
}

Zend/zend_object_handlers.h

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -277,12 +277,6 @@ ZEND_API HashTable *rebuild_object_properties_internal(zend_object *zobj);
277277
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);
278278
ZEND_API ZEND_COLD zend_never_inline void zend_abstract_method_call(const zend_function *fbc);
279279

280-
/* Check if a readonly property has the REINITABLE flag (set by clone or CPP initialization) */
281-
static zend_always_inline bool zend_readonly_property_is_reinitable(const zval *property_val)
282-
{
283-
return (Z_PROP_FLAG_P(property_val) & IS_PROP_REINITABLE) != 0;
284-
}
285-
286280
static zend_always_inline HashTable *zend_std_get_properties_ex(zend_object *object)
287281
{
288282
if (UNEXPECTED(zend_lazy_object_must_init(object))) {

0 commit comments

Comments
 (0)