Skip to content

Commit 287aeeb

Browse files
committed
Merge branch 'PHP-8.4'
* PHP-8.4: Fix incorrect dynamic prop offset in hooked prop iterator
2 parents b2c891f + f044174 commit 287aeeb

File tree

2 files changed

+46
-5
lines changed

2 files changed

+46
-5
lines changed
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
--TEST--
2+
GH-17200: Incorrect dynamic property offset
3+
--FILE--
4+
<?php
5+
6+
class A {
7+
public $prop;
8+
}
9+
10+
class B extends A {
11+
public $prop {
12+
get => $this->prop;
13+
}
14+
}
15+
16+
$b = new B();
17+
var_dump($b);
18+
echo json_encode($b), "\n";
19+
20+
?>
21+
--EXPECTF--
22+
object(B)#%d (1) {
23+
["prop"]=>
24+
NULL
25+
}
26+
{"prop":null}

Zend/zend_property_hooks.c

Lines changed: 20 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ typedef struct {
2828
bool declared_props_done;
2929
zval declared_props;
3030
bool dynamic_props_done;
31+
uint32_t dynamic_prop_offset;
3132
uint32_t dynamic_prop_it;
3233
zval current_key;
3334
zval current_data;
@@ -36,9 +37,19 @@ typedef struct {
3637
static zend_result zho_it_valid(zend_object_iterator *iter);
3738
static void zho_it_move_forward(zend_object_iterator *iter);
3839

39-
static uint32_t zho_num_backed_props(zend_object *zobj)
40+
static uint32_t zho_find_dynamic_prop_offset(zend_array *properties)
4041
{
41-
return zobj->ce->default_properties_count;
42+
uint32_t offset = 0;
43+
zval *value;
44+
45+
ZEND_HASH_MAP_FOREACH_VAL(properties, value) {
46+
if (Z_TYPE_P(value) != IS_INDIRECT) {
47+
break;
48+
}
49+
offset++;
50+
} ZEND_HASH_FOREACH_END();
51+
52+
return offset;
4253
}
4354

4455
static zend_array *zho_build_properties_ex(zend_object *zobj, bool check_access, bool force_ptr, bool include_dynamic_props)
@@ -106,7 +117,10 @@ static zend_array *zho_build_properties_ex(zend_object *zobj, bool check_access,
106117
if (include_dynamic_props && zobj->properties) {
107118
zend_string *prop_name;
108119
zval *prop_value;
109-
ZEND_HASH_FOREACH_STR_KEY_VAL_FROM(zobj->properties, prop_name, prop_value, zho_num_backed_props(zobj)) {
120+
ZEND_HASH_FOREACH_STR_KEY_VAL(zobj->properties, prop_name, prop_value) {
121+
if (Z_TYPE_P(prop_value) == IS_INDIRECT) {
122+
continue;
123+
}
110124
zval *tmp = _zend_hash_append(properties, prop_name, prop_value);
111125
Z_TRY_ADDREF_P(tmp);
112126
} ZEND_HASH_FOREACH_END();
@@ -132,7 +146,8 @@ static void zho_dynamic_it_init(zend_hooked_object_iterator *hooked_iter)
132146
zend_object *zobj = Z_OBJ_P(&hooked_iter->it.data);
133147
zend_array *properties = zobj->handlers->get_properties(zobj);
134148
hooked_iter->dynamic_props_done = false;
135-
hooked_iter->dynamic_prop_it = zend_hash_iterator_add(properties, zho_num_backed_props(zobj));
149+
hooked_iter->dynamic_prop_offset = zho_find_dynamic_prop_offset(properties);
150+
hooked_iter->dynamic_prop_it = zend_hash_iterator_add(properties, hooked_iter->dynamic_prop_offset);
136151
}
137152

138153
static void zho_it_get_current_key(zend_object_iterator *iter, zval *key);
@@ -324,7 +339,7 @@ static void zho_it_rewind(zend_object_iterator *iter)
324339
zend_hash_internal_pointer_reset(properties);
325340
hooked_iter->declared_props_done = !zend_hash_num_elements(properties);
326341
hooked_iter->dynamic_props_done = false;
327-
EG(ht_iterators)[hooked_iter->dynamic_prop_it].pos = zho_num_backed_props(Z_OBJ(iter->data));
342+
EG(ht_iterators)[hooked_iter->dynamic_prop_it].pos = hooked_iter->dynamic_prop_offset;
328343
}
329344

330345
static HashTable *zho_it_get_gc(zend_object_iterator *iter, zval **table, int *n)

0 commit comments

Comments
 (0)