Skip to content

Commit abfa463

Browse files
committed
Adjust for lazy proxies
1 parent 6c2e97b commit abfa463

File tree

2 files changed

+22
-11
lines changed

2 files changed

+22
-11
lines changed

Zend/tests/gh18845.phpt

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,11 +17,13 @@ var_dump($c->prop ?? 1);
1717

1818
$r = new ReflectionClass(C::class);
1919
$c = $r->newLazyProxy(function () {
20-
throw new Exception('Not reached');
20+
$c = new C();
21+
$c->prop = 2;
22+
return $c;
2123
});
2224
var_dump($c->prop ?? 1);
2325

2426
?>
2527
--EXPECT--
2628
int(1)
27-
int(1)
29+
int(2)

Zend/zend_object_handlers.c

Lines changed: 18 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -733,6 +733,8 @@ ZEND_API zval *zend_std_read_property(zend_object *zobj, zend_string *name, int
733733
uintptr_t property_offset;
734734
const zend_property_info *prop_info = NULL;
735735
uint32_t *guard = NULL;
736+
bool obj_needs_deref = false;
737+
zend_object *prev_zobj;
736738

737739
#if DEBUG_OBJECT_HANDLERS
738740
fprintf(stderr, "Read object #%d property: %s\n", zobj->handle, ZSTR_VAL(name));
@@ -906,12 +908,8 @@ ZEND_API zval *zend_std_read_property(zend_object *zobj, zend_string *name, int
906908
goto call_getter;
907909
}
908910

909-
bool obj_is_freed = GC_REFCOUNT(zobj) == 1;
910-
OBJ_RELEASE(zobj);
911-
if (UNEXPECTED(obj_is_freed)) {
912-
retval = &EG(uninitialized_zval);
913-
goto exit;
914-
}
911+
obj_needs_deref = true;
912+
prev_zobj = zobj;
915913
} else if (zobj->ce->__get && !((*guard) & IN_GET)) {
916914
goto call_getter_addref;
917915
}
@@ -960,7 +958,7 @@ ZEND_API zval *zend_std_read_property(zend_object *zobj, zend_string *name, int
960958
zobj = zend_lazy_object_init(zobj);
961959
if (!zobj) {
962960
retval = &EG(uninitialized_zval);
963-
goto exit;
961+
goto exit_slow;
964962
}
965963

966964
if (UNEXPECTED(guard)) {
@@ -971,11 +969,12 @@ ZEND_API zval *zend_std_read_property(zend_object *zobj, zend_string *name, int
971969
(*guard) |= guard_type;
972970
retval = zend_std_read_property(zobj, name, type, cache_slot, rv);
973971
(*guard) &= ~guard_type;
974-
return retval;
972+
goto exit_slow;
975973
}
976974
}
977975

978-
return zend_std_read_property(zobj, name, type, cache_slot, rv);
976+
retval = zend_std_read_property(zobj, name, type, cache_slot, rv);
977+
goto exit_slow;
979978
}
980979
}
981980
if (type != BP_VAR_IS) {
@@ -987,6 +986,16 @@ ZEND_API zval *zend_std_read_property(zend_object *zobj, zend_string *name, int
987986
}
988987
retval = &EG(uninitialized_zval);
989988

989+
exit_slow:
990+
if (obj_needs_deref) {
991+
/* Move value to rv in case zobj gets destroyed. */
992+
if (retval != rv) {
993+
ZVAL_COPY(rv, retval);
994+
retval = rv;
995+
}
996+
OBJ_RELEASE(prev_zobj);
997+
}
998+
990999
exit:
9911000
return retval;
9921001
}

0 commit comments

Comments
 (0)