Skip to content

Fix incorrect dynamic prop offset in hooked prop iterator #17203

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 26 additions & 0 deletions Zend/tests/property_hooks/gh17200.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
--TEST--
GH-17200: Incorrect dynamic property offset
--FILE--
<?php

class A {
public $prop;
}

class B extends A {
public $prop {
get => $this->prop;
}
}

$b = new B();
var_dump($b);
echo json_encode($b), "\n";

?>
--EXPECTF--
object(B)#%d (1) {
["prop"]=>
NULL
}
{"prop":null}
25 changes: 20 additions & 5 deletions Zend/zend_property_hooks.c
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ typedef struct {
bool declared_props_done;
zval declared_props;
bool dynamic_props_done;
uint32_t dynamic_prop_offset;
uint32_t dynamic_prop_it;
zval current_key;
zval current_data;
Expand All @@ -36,9 +37,19 @@ typedef struct {
static zend_result zho_it_valid(zend_object_iterator *iter);
static void zho_it_move_forward(zend_object_iterator *iter);

static uint32_t zho_num_backed_props(zend_object *zobj)
static uint32_t zho_find_dynamic_prop_offset(zend_array *properties)
{
return zobj->ce->default_properties_count;
uint32_t offset = 0;
zval *value;

ZEND_HASH_MAP_FOREACH_VAL(properties, value) {
if (Z_TYPE_P(value) != IS_INDIRECT) {
break;
}
offset++;
} ZEND_HASH_FOREACH_END();

return offset;
}

static zend_array *zho_build_properties_ex(zend_object *zobj, bool check_access, bool force_ptr, bool include_dynamic_props)
Expand Down Expand Up @@ -106,7 +117,10 @@ static zend_array *zho_build_properties_ex(zend_object *zobj, bool check_access,
if (include_dynamic_props && zobj->properties) {
zend_string *prop_name;
zval *prop_value;
ZEND_HASH_FOREACH_STR_KEY_VAL_FROM(zobj->properties, prop_name, prop_value, zho_num_backed_props(zobj)) {
ZEND_HASH_FOREACH_STR_KEY_VAL(zobj->properties, prop_name, prop_value) {
if (Z_TYPE_P(prop_value) == IS_INDIRECT) {
continue;
}
zval *tmp = _zend_hash_append(properties, prop_name, prop_value);
Z_TRY_ADDREF_P(tmp);
} ZEND_HASH_FOREACH_END();
Expand All @@ -132,7 +146,8 @@ static void zho_dynamic_it_init(zend_hooked_object_iterator *hooked_iter)
zend_object *zobj = Z_OBJ_P(&hooked_iter->it.data);
zend_array *properties = zobj->handlers->get_properties(zobj);
hooked_iter->dynamic_props_done = false;
hooked_iter->dynamic_prop_it = zend_hash_iterator_add(properties, zho_num_backed_props(zobj));
hooked_iter->dynamic_prop_offset = zho_find_dynamic_prop_offset(properties);
hooked_iter->dynamic_prop_it = zend_hash_iterator_add(properties, hooked_iter->dynamic_prop_offset);
}

static void zho_it_get_current_key(zend_object_iterator *iter, zval *key);
Expand Down Expand Up @@ -324,7 +339,7 @@ static void zho_it_rewind(zend_object_iterator *iter)
zend_hash_internal_pointer_reset(properties);
hooked_iter->declared_props_done = !zend_hash_num_elements(properties);
hooked_iter->dynamic_props_done = false;
EG(ht_iterators)[hooked_iter->dynamic_prop_it].pos = zho_num_backed_props(Z_OBJ(iter->data));
EG(ht_iterators)[hooked_iter->dynamic_prop_it].pos = hooked_iter->dynamic_prop_offset;
}

static HashTable *zho_it_get_gc(zend_object_iterator *iter, zval **table, int *n)
Expand Down
Loading