Skip to content

Commit 6bde436

Browse files
committed
Don't call __set() on uninitialized typed properties, take 2
1 parent 4d8541d commit 6bde436

File tree

7 files changed

+49
-5
lines changed

7 files changed

+49
-5
lines changed
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
--TEST--
2+
__set() should not be invoked when setting an uninitialized typed property
3+
--FILE--
4+
<?php
5+
class Test {
6+
public int $foo;
7+
public function __set($name, $value) {
8+
echo "__set ", $name, " = ", $value, "\n";
9+
}
10+
}
11+
$test = new Test;
12+
$test->foo = 42;
13+
var_dump($test->foo);
14+
// __set will be called after unset()
15+
unset($test->foo);
16+
$test->foo = 42;
17+
// __set will be called after unset() without prior initialization
18+
$test = new Test;
19+
unset($test->foo);
20+
$test->foo = 42;
21+
?>
22+
--EXPECT--
23+
int(42)
24+
__set foo = 42
25+
__set foo = 42

Zend/zend_API.c

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1264,12 +1264,14 @@ static zend_always_inline void _object_properties_init(zend_object *object, zend
12641264
if (UNEXPECTED(class_type->type == ZEND_INTERNAL_CLASS)) {
12651265
do {
12661266
ZVAL_COPY_OR_DUP(dst, src);
1267+
Z_EXTRA_P(dst) = Z_EXTRA_P(src);
12671268
src++;
12681269
dst++;
12691270
} while (src != end);
12701271
} else {
12711272
do {
12721273
ZVAL_COPY(dst, src);
1274+
Z_EXTRA_P(dst) = Z_EXTRA_P(src);
12731275
src++;
12741276
dst++;
12751277
} while (src != end);
@@ -3683,6 +3685,7 @@ static zend_always_inline zend_bool is_persistent_class(zend_class_entry *ce) {
36833685
ZEND_API int zend_declare_typed_property(zend_class_entry *ce, zend_string *name, zval *property, int access_type, zend_string *doc_comment, zend_type type) /* {{{ */
36843686
{
36853687
zend_property_info *property_info, *property_info_ptr;
3688+
zval *property_default_ptr;
36863689

36873690
if (ZEND_TYPE_IS_SET(type)) {
36883691
ce->ce_flags |= ZEND_ACC_HAS_TYPE_HINTS;
@@ -3714,7 +3717,7 @@ ZEND_API int zend_declare_typed_property(zend_class_entry *ce, zend_string *name
37143717
property_info->offset = ce->default_static_members_count++;
37153718
ce->default_static_members_table = perealloc(ce->default_static_members_table, sizeof(zval) * ce->default_static_members_count, ce->type == ZEND_INTERNAL_CLASS);
37163719
}
3717-
ZVAL_COPY_VALUE(&ce->default_static_members_table[property_info->offset], property);
3720+
property_default_ptr = &ce->default_static_members_table[property_info->offset];
37183721
if (!ZEND_MAP_PTR(ce->static_members_table)) {
37193722
ZEND_ASSERT(ce->type == ZEND_INTERNAL_CLASS);
37203723
if (!EG(current_execute_data)) {
@@ -3745,7 +3748,7 @@ ZEND_API int zend_declare_typed_property(zend_class_entry *ce, zend_string *name
37453748
ce->properties_info_table[ce->default_properties_count - 1] = property_info;
37463749
}
37473750
}
3748-
ZVAL_COPY_VALUE(&ce->default_properties_table[OBJ_PROP_TO_NUM(property_info->offset)], property);
3751+
property_default_ptr = &ce->default_properties_table[OBJ_PROP_TO_NUM(property_info->offset)];
37493752
}
37503753
if (ce->type & ZEND_INTERNAL_CLASS) {
37513754
switch(Z_TYPE_P(property)) {
@@ -3762,6 +3765,9 @@ ZEND_API int zend_declare_typed_property(zend_class_entry *ce, zend_string *name
37623765
name = zend_new_interned_string(zend_string_copy(name));
37633766
}
37643767

3768+
ZVAL_COPY_VALUE(property_default_ptr, property);
3769+
Z_EXTRA_P(property_default_ptr) = Z_ISUNDEF_P(property) ? IS_PROP_UNINIT : 0;
3770+
37653771
if (access_type & ZEND_ACC_PUBLIC) {
37663772
property_info->name = zend_string_copy(name);
37673773
} else if (access_type & ZEND_ACC_PRIVATE) {

Zend/zend_inheritance.c

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1167,7 +1167,7 @@ ZEND_API void zend_do_inheritance_ex(zend_class_entry *ce, zend_class_entry *par
11671167
do {
11681168
dst--;
11691169
src--;
1170-
ZVAL_COPY_VALUE(dst, src);
1170+
*dst = *src; /* Copy Z_EXTRA as well */
11711171
} while (dst != end);
11721172
pefree(src, ce->type == ZEND_INTERNAL_CLASS);
11731173
end = ce->default_properties_table;
@@ -1182,7 +1182,9 @@ ZEND_API void zend_do_inheritance_ex(zend_class_entry *ce, zend_class_entry *par
11821182
do {
11831183
dst--;
11841184
src--;
1185+
*dst = *src; /* Copy Z_EXTRA as well */
11851186
ZVAL_COPY_OR_DUP(dst, src);
1187+
Z_EXTRA_P(dst) = Z_EXTRA_P(src);
11861188
if (Z_OPT_TYPE_P(dst) == IS_CONSTANT_AST) {
11871189
ce->ce_flags &= ~ZEND_ACC_CONSTANTS_UPDATED;
11881190
}
@@ -1193,6 +1195,7 @@ ZEND_API void zend_do_inheritance_ex(zend_class_entry *ce, zend_class_entry *par
11931195
dst--;
11941196
src--;
11951197
ZVAL_COPY(dst, src);
1198+
Z_EXTRA_P(dst) = Z_EXTRA_P(src);
11961199
if (Z_OPT_TYPE_P(dst) == IS_CONSTANT_AST) {
11971200
ce->ce_flags &= ~ZEND_ACC_CONSTANTS_UPDATED;
11981201
}

Zend/zend_object_handlers.c

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -836,6 +836,11 @@ ZEND_API zval *zend_std_write_property(zval *object, zval *member, zval *value,
836836
zend_assign_to_variable(variable_ptr, value, IS_TMP_VAR, EG(current_execute_data) && ZEND_CALL_USES_STRICT_TYPES(EG(current_execute_data)));
837837
goto exit;
838838
}
839+
if (Z_EXTRA_P(variable_ptr) == IS_PROP_UNINIT) {
840+
/* Writes to uninitializde typed properties bypass __set(). */
841+
Z_EXTRA_P(variable_ptr) = 0;
842+
goto write_std_property;
843+
}
839844
} else if (EXPECTED(IS_DYNAMIC_PROPERTY_OFFSET(property_offset))) {
840845
if (EXPECTED(zobj->properties != NULL)) {
841846
if (UNEXPECTED(GC_REFCOUNT(zobj->properties) > 1)) {
@@ -1113,6 +1118,8 @@ ZEND_API void zend_std_unset_property(zval *object, zval *member, void **cache_s
11131118
}
11141119
goto exit;
11151120
}
1121+
/* Reset the IS_PROP_UNINIT flag, if it exists. */
1122+
Z_EXTRA_P(slot) = 0;
11161123
} else if (EXPECTED(IS_DYNAMIC_PROPERTY_OFFSET(property_offset))
11171124
&& EXPECTED(zobj->properties != NULL)) {
11181125
if (UNEXPECTED(GC_REFCOUNT(zobj->properties) > 1)) {

Zend/zend_objects.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -209,7 +209,7 @@ ZEND_API void ZEND_FASTCALL zend_objects_clone_members(zend_object *new_object,
209209

210210
do {
211211
i_zval_ptr_dtor(dst);
212-
ZVAL_COPY_VALUE(dst, src);
212+
*dst = *src; /* Copy Z_EXTRA as well */
213213
zval_add_ref(dst);
214214
if (UNEXPECTED(Z_ISREF_P(dst)) &&
215215
(ZEND_DEBUG || ZEND_REF_HAS_TYPE_SOURCES(Z_REF_P(dst)))) {

Zend/zend_types.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -593,6 +593,9 @@ static zend_always_inline uint32_t zval_gc_info(uint32_t gc_type_info) {
593593

594594
#define OBJ_FLAGS(obj) GC_FLAGS(obj)
595595

596+
/* Property flag stores in Z_EXTRA */
597+
#define IS_PROP_UNINIT 1
598+
596599
/* Recursion protection macros must be used only for arrays and objects */
597600
#define GC_IS_RECURSIVE(p) \
598601
(GC_FLAGS(p) & GC_PROTECTED)

ext/opcache/zend_accelerator_util_funcs.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -270,7 +270,7 @@ static void zend_class_copy_ctor(zend_class_entry **pce)
270270
end = src + ce->default_properties_count;
271271
ce->default_properties_table = dst;
272272
for (; src != end; src++, dst++) {
273-
ZVAL_COPY_VALUE(dst, src);
273+
*dst = *src;
274274
}
275275
}
276276

0 commit comments

Comments
 (0)