]> granicus.if.org Git - php/commitdiff
Remove properties HT from nested GC data
authorNikita Popov <nikita.ppv@gmail.com>
Mon, 26 Aug 2019 15:48:05 +0000 (17:48 +0200)
committerNikita Popov <nikita.ppv@gmail.com>
Mon, 26 Aug 2019 15:49:37 +0000 (17:49 +0200)
The properties HT may be a GC root itself, so we need to remove it.
I'm not sure this issue actually applies to PHP 7.2, but committing
it there to be safe. As seen from the test case, the handling here
is rather buggy on 7.2.

Zend/tests/gc_042.phpt [new file with mode: 0644]
Zend/zend_gc.c

diff --git a/Zend/tests/gc_042.phpt b/Zend/tests/gc_042.phpt
new file mode 100644 (file)
index 0000000..a7c40fe
--- /dev/null
@@ -0,0 +1,26 @@
+--TEST--
+Object properties HT may need to be removed from nested data
+--FILE--
+<?php
+
+class Test {
+    public function __destruct() {
+        $GLOBALS['x'] = $this;
+    }
+}
+
+$t = new Test;
+$t->x = new stdClass;
+$t->x->t = $t;
+$a = (array) $t->x;
+unset($t, $a);
+gc_collect_cycles();
+var_dump($x);
+
+// TODO: The destructor *should* be running here, but doesn't.
+// This works in PHP >= 7.3 though.
+
+?>
+--EXPECTF--
+Notice: Undefined variable: x in %s on line %d
+NULL
index d98598cc48f87f5cf24ee27d425a7176ebe98378..1b6d53a83d97b9a3893fd6e0d25ba1f36d14544a 100644 (file)
@@ -1007,6 +1007,10 @@ tail_call:
                                        ref = Z_COUNTED_P(zv);
                                        goto tail_call;
                                }
+                               if (GC_ADDRESS(GC_INFO(ht)) != 0 && GC_REF_GET_COLOR(ht) == GC_BLACK) {
+                                       GC_TRACE_REF(ht, "removing from buffer");
+                                       GC_REMOVE_FROM_BUFFER(ht);
+                               }
                        } else {
                                return;
                        }