summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNikita Popov <nikita.ppv@gmail.com>2020-08-31 12:17:00 +0200
committerNikita Popov <nikita.ppv@gmail.com>2020-08-31 12:17:00 +0200
commitdfaa4768d28061c1012dc0a0be465a672bd446d8 (patch)
treefd471bcb80f902b6285688be11b140739b31cede
parent8f7c52972089ad7ca6349a036a9cef6da5c4146e (diff)
downloadphp-git-dfaa4768d28061c1012dc0a0be465a672bd446d8.tar.gz
Fix bug #80037
If we're accessing an uninitialized typed property and __get is defined, don't perform a read_property callback, as __get is supposed to have no effect on uninitialized typed properties. Usually it doesn't, but by-reference assignments cannot be performed through read_property. I'm deleting the test for bug #80039 again, as it doesn't really make sense anymore with this fix.
-rw-r--r--NEWS2
-rw-r--r--Zend/tests/bug80037.phpt32
-rw-r--r--Zend/tests/bug80039.phpt43
-rw-r--r--Zend/zend_object_handlers.c3
4 files changed, 36 insertions, 44 deletions
diff --git a/NEWS b/NEWS
index 76812d06dd..e2cb05e949 100644
--- a/NEWS
+++ b/NEWS
@@ -5,6 +5,8 @@ PHP NEWS
- Core:
. Fixed bug #79979 (passing value to by-ref param via CUFA crashes). (cmb,
Nikita)
+ . Fixed bug #80037 (Typed property must not be accessed before initialization
+ when __get() declared). (Nikita)
- Calendar:
. Fixed bug #80007 (Potential type confusion in unixtojd() parameter parsing).
diff --git a/Zend/tests/bug80037.phpt b/Zend/tests/bug80037.phpt
new file mode 100644
index 0000000000..7bbe6128b3
--- /dev/null
+++ b/Zend/tests/bug80037.phpt
@@ -0,0 +1,32 @@
+--TEST--
+Bug #80037: Typed property must not be accessed before initialization when __get() declared
+--FILE--
+<?php
+
+final class A
+{
+ public string $a;
+
+ public static function fromArray(array $props): self
+ {
+ $me = new static;
+ foreach ($props as $k => &$v) {
+ $me->{$k} = &$v; # try to remove &
+ }
+ return $me;
+ }
+
+ public function __get($name)
+ {
+ throw new \LogicException("Property '$name' is not defined.");
+ }
+}
+
+var_dump(A::fromArray(['a' => 'foo']));
+
+?>
+--EXPECT--
+object(A)#1 (1) {
+ ["a"]=>
+ string(3) "foo"
+}
diff --git a/Zend/tests/bug80039.phpt b/Zend/tests/bug80039.phpt
deleted file mode 100644
index e04732f43c..0000000000
--- a/Zend/tests/bug80039.phpt
+++ /dev/null
@@ -1,43 +0,0 @@
---TEST--
-Bug #80039: Illegal string offset and Cannot create references to/from string offsets
---FILE--
-<?php
-
-final class A
-{
- public string $a;
-
- public static function fromArray(array $props): self
- {
- $me = new static;
- foreach ($props as $k => &$v) {
- $me->{$k} = &$v;
- }
- return $me;
- }
-
- public function __get($name)
- {
- throw new \LogicException("Property '$name' is not defined.");
- }
-}
-
-class ObjectHelpers
-{
- public static function hasProperty(string $class, string $name)
- {
- static $cache = [];
- $prop = &$cache[$class][$name]; # <-- emits error
- var_dump($prop);
- }
-}
-
-set_exception_handler(function ($e) {
- ObjectHelpers::hasProperty(A::class, 'a');
-});
-
-A::fromArray(['a' => 'foo']);
-
-?>
---EXPECT--
-NULL
diff --git a/Zend/zend_object_handlers.c b/Zend/zend_object_handlers.c
index c058c1cf49..e1220ad0ee 100644
--- a/Zend/zend_object_handlers.c
+++ b/Zend/zend_object_handlers.c
@@ -1051,7 +1051,8 @@ ZEND_API zval *zend_std_get_property_ptr_ptr(zval *object, zval *member, int typ
retval = OBJ_PROP(zobj, property_offset);
if (UNEXPECTED(Z_TYPE_P(retval) == IS_UNDEF)) {
if (EXPECTED(!zobj->ce->__get) ||
- UNEXPECTED((*zend_get_property_guard(zobj, name)) & IN_GET)) {
+ UNEXPECTED((*zend_get_property_guard(zobj, name)) & IN_GET) ||
+ UNEXPECTED(prop_info && Z_PROP_FLAG_P(retval) == IS_PROP_UNINIT)) {
if (UNEXPECTED(type == BP_VAR_RW || type == BP_VAR_R)) {
if (UNEXPECTED(prop_info)) {
zend_throw_error(NULL,