]> granicus.if.org Git - php/commitdiff
Fix bug #80037
authorNikita Popov <nikita.ppv@gmail.com>
Mon, 31 Aug 2020 10:17:00 +0000 (12:17 +0200)
committerNikita Popov <nikita.ppv@gmail.com>
Mon, 31 Aug 2020 10:17:00 +0000 (12:17 +0200)
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.

NEWS
Zend/tests/bug80037.phpt [new file with mode: 0644]
Zend/tests/bug80039.phpt [deleted file]
Zend/zend_object_handlers.c

diff --git a/NEWS b/NEWS
index 76812d06dd2c1fba8d0795c20738da8b8b908fa1..e2cb05e949509caa0ee02ab8b165a611fad44d0f 100644 (file)
--- 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 (file)
index 0000000..7bbe612
--- /dev/null
@@ -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 (file)
index e04732f..0000000
+++ /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
index c058c1cf497a27b34711f4bf8256bf0c110e21b6..e1220ad0ee6ade9adb2f773f6d8fabddc5dc3d9b 100644 (file)
@@ -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,