diff options
author | Nikita Popov <nikita.ppv@gmail.com> | 2020-08-31 12:17:00 +0200 |
---|---|---|
committer | Nikita Popov <nikita.ppv@gmail.com> | 2020-08-31 12:17:00 +0200 |
commit | dfaa4768d28061c1012dc0a0be465a672bd446d8 (patch) | |
tree | fd471bcb80f902b6285688be11b140739b31cede | |
parent | 8f7c52972089ad7ca6349a036a9cef6da5c4146e (diff) | |
download | php-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-- | NEWS | 2 | ||||
-rw-r--r-- | Zend/tests/bug80037.phpt | 32 | ||||
-rw-r--r-- | Zend/tests/bug80039.phpt | 43 | ||||
-rw-r--r-- | Zend/zend_object_handlers.c | 3 |
4 files changed, 36 insertions, 44 deletions
@@ -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, |