Skip to content

Commit

Permalink
Repeat dynamic property check after __isset for ??
Browse files Browse the repository at this point in the history
  • Loading branch information
iluuu1994 committed Nov 17, 2023
1 parent 6f95273 commit 4df25e1
Show file tree
Hide file tree
Showing 2 changed files with 62 additions and 25 deletions.
22 changes: 22 additions & 0 deletions Zend/tests/coalesce_is_create_property.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
--TEST--
Coalesce IS fetch should repeat dynamic property check after __isset
--FILE--
<?php
#[AllowDynamicProperties]
class A {
public function __isset($prop) {
echo __FUNCTION__, "\n";
$this->$prop = 123;
return true;
}
public function __get($prop) {
throw new Exception('Unreachable');
}
}

$a = new A;
echo $a->foo ?? 234;
?>
--EXPECT--
__isset
123
65 changes: 40 additions & 25 deletions Zend/zend_object_handlers.c
Original file line number Diff line number Diff line change
Expand Up @@ -604,6 +604,36 @@ ZEND_API uint32_t *zend_get_recursion_guard(zend_object *zobj)
return &Z_GUARD_P(zv);
}

static zval *zend_std_read_dynamic_property(zend_object *zobj, zend_string *name, void **cache_slot, uintptr_t property_offset)
{
if (EXPECTED(zobj->properties != NULL)) {
if (!IS_UNKNOWN_DYNAMIC_PROPERTY_OFFSET(property_offset)) {
uintptr_t idx = ZEND_DECODE_DYN_PROP_OFFSET(property_offset);

if (EXPECTED(idx < zobj->properties->nNumUsed * sizeof(Bucket))) {
Bucket *p = (Bucket*)((char*)zobj->properties->arData + idx);

if (EXPECTED(p->key == name) ||
(EXPECTED(p->h == ZSTR_H(name)) &&
EXPECTED(p->key != NULL) &&
EXPECTED(zend_string_equal_content(p->key, name)))) {
return &p->val;
}
}
CACHE_PTR_EX(cache_slot + 1, (void*)ZEND_DYNAMIC_PROPERTY_OFFSET);
}
zval *retval = zend_hash_find(zobj->properties, name);
if (EXPECTED(retval)) {
if (cache_slot) {
uintptr_t idx = (char*)retval - (char*)zobj->properties->arData;
CACHE_PTR_EX(cache_slot + 1, (void*)ZEND_ENCODE_DYN_PROP_OFFSET(idx));
}
return retval;
}
}
return NULL;
}

ZEND_API zval *zend_std_read_property(zend_object *zobj, zend_string *name, int type, void **cache_slot, zval *rv) /* {{{ */
{
zval *retval;
Expand Down Expand Up @@ -655,31 +685,9 @@ ZEND_API zval *zend_std_read_property(zend_object *zobj, zend_string *name, int
goto uninit_error;
}
} else if (EXPECTED(IS_DYNAMIC_PROPERTY_OFFSET(property_offset))) {
if (EXPECTED(zobj->properties != NULL)) {
if (!IS_UNKNOWN_DYNAMIC_PROPERTY_OFFSET(property_offset)) {
uintptr_t idx = ZEND_DECODE_DYN_PROP_OFFSET(property_offset);

if (EXPECTED(idx < zobj->properties->nNumUsed * sizeof(Bucket))) {
Bucket *p = (Bucket*)((char*)zobj->properties->arData + idx);

if (EXPECTED(p->key == name) ||
(EXPECTED(p->h == ZSTR_H(name)) &&
EXPECTED(p->key != NULL) &&
EXPECTED(zend_string_equal_content(p->key, name)))) {
retval = &p->val;
goto exit;
}
}
CACHE_PTR_EX(cache_slot + 1, (void*)ZEND_DYNAMIC_PROPERTY_OFFSET);
}
retval = zend_hash_find(zobj->properties, name);
if (EXPECTED(retval)) {
if (cache_slot) {
uintptr_t idx = (char*)retval - (char*)zobj->properties->arData;
CACHE_PTR_EX(cache_slot + 1, (void*)ZEND_ENCODE_DYN_PROP_OFFSET(idx));
}
goto exit;
}
retval = zend_std_read_dynamic_property(zobj, name, cache_slot, property_offset);
if (retval) {
goto exit;
}
} else if (UNEXPECTED(EG(exception))) {
retval = &EG(uninitialized_zval);
Expand Down Expand Up @@ -710,6 +718,13 @@ ZEND_API zval *zend_std_read_property(zend_object *zobj, zend_string *name, int
}

zval_ptr_dtor(&tmp_result);

retval = zend_std_read_dynamic_property(zobj, name, cache_slot, property_offset);
if (retval) {
OBJ_RELEASE(zobj);
goto exit;
}

if (zobj->ce->__get && !((*guard) & IN_GET)) {
goto call_getter;
}
Expand Down

0 comments on commit 4df25e1

Please sign in to comment.