php/backport-Undef-slot-before-destroying-in-unset_property.patch
2021-12-18 15:27:36 +08:00

106 lines
2.4 KiB
Diff

From ebd3a210021ec3b8f210822f0c69ee8f3132f1dc Mon Sep 17 00:00:00 2001
From: Nikita Popov <nikita.ppv@gmail.com>
Date: Thu, 15 Jul 2021 09:29:08 +0200
Subject: [PATCH] Undef slot before destroying in unset_property
We need to make sure that destructors can't access the partially
destroyed property. Do the same we do in HTs.
Fixes oss-fuzz #36205.
---
Zend/tests/unset_prop_recursion.phpt | 65 ++++++++++++++++++++++++++++++++++++
Zend/zend_object_handlers.c | 4 ++-
2 files changed, 68 insertions(+), 1 deletion(-)
create mode 100644 Zend/tests/unset_prop_recursion.phpt
diff --git a/Zend/tests/unset_prop_recursion.phpt b/Zend/tests/unset_prop_recursion.phpt
new file mode 100644
index 0000000..afb1929
--- /dev/null
+++ b/Zend/tests/unset_prop_recursion.phpt
@@ -0,0 +1,65 @@
+--TEST--
+Unset property where unset will recursively access property again
+--FILE--
+<?php
+class Node {
+ public $parent = null;
+ public $children = [];
+ function insert(Node $node) {
+ $node->parent = $this;
+ $this->children[] = $node;
+ }
+ function __destruct() {
+ var_dump($this);
+ unset($this->children);
+ }
+}
+
+$a = new Node;
+$a->insert(new Node);
+$a->insert(new Node);
+?>
+--EXPECT--
+object(Node)#1 (2) {
+ ["parent"]=>
+ NULL
+ ["children"]=>
+ array(2) {
+ [0]=>
+ object(Node)#2 (2) {
+ ["parent"]=>
+ *RECURSION*
+ ["children"]=>
+ array(0) {
+ }
+ }
+ [1]=>
+ object(Node)#3 (2) {
+ ["parent"]=>
+ *RECURSION*
+ ["children"]=>
+ array(0) {
+ }
+ }
+ }
+}
+object(Node)#2 (2) {
+ ["parent"]=>
+ object(Node)#1 (2) {
+ ["parent"]=>
+ NULL
+ }
+ ["children"]=>
+ array(0) {
+ }
+}
+object(Node)#3 (2) {
+ ["parent"]=>
+ object(Node)#1 (2) {
+ ["parent"]=>
+ NULL
+ }
+ ["children"]=>
+ array(0) {
+ }
+}
diff --git a/Zend/zend_object_handlers.c b/Zend/zend_object_handlers.c
index 7c2bd13..e61a5af 100644
--- a/Zend/zend_object_handlers.c
+++ b/Zend/zend_object_handlers.c
@@ -1137,8 +1137,10 @@ ZEND_API void zend_std_unset_property(zval *object, zval *member, void **cache_s
ZEND_REF_DEL_TYPE_SOURCE(Z_REF_P(slot), prop_info);
}
}
- zval_ptr_dtor(slot);
+ zval tmp;
+ ZVAL_COPY_VALUE(&tmp, slot);
ZVAL_UNDEF(slot);
+ zval_ptr_dtor(&tmp);
if (zobj->properties) {
HT_FLAGS(zobj->properties) |= HASH_FLAG_HAS_EMPTY_IND;
}
--
1.8.3.1