]> granicus.if.org Git - php/commitdiff
Fixed handling of references in nested data of objects with destructor
authorDmitry Stogov <dmitry@zend.com>
Fri, 9 Aug 2019 14:43:50 +0000 (17:43 +0300)
committerDmitry Stogov <dmitry@zend.com>
Fri, 9 Aug 2019 14:43:50 +0000 (17:43 +0300)
Zend/tests/gc_041.phpt [new file with mode: 0644]
Zend/zend_gc.c

diff --git a/Zend/tests/gc_041.phpt b/Zend/tests/gc_041.phpt
new file mode 100644 (file)
index 0000000..7400e23
--- /dev/null
@@ -0,0 +1,35 @@
+--TEST--
+GC 041: Handling of references in nested data of objects with destructor
+--INI--
+zend.enable_gc = 1
+--FILE--
+<?php
+class ryat {
+           var $ryat;
+        var $chtg;
+        var $nested;
+           function __destruct() {
+                   $GLOBALS['x'] = $this;
+        }
+}
+$o = new ryat;
+$o->nested = [];
+$o->nested[] =& $o->nested;
+$o->ryat = $o;
+$x =& $o->chtg;
+unset($o);
+gc_collect_cycles();
+var_dump($x);
+?>
+--EXPECT--
+object(ryat)#1 (3) {
+  ["ryat"]=>
+  *RECURSION*
+  ["chtg"]=>
+  *RECURSION*
+  ["nested"]=>
+  &array(1) {
+    [0]=>
+    *RECURSION*
+  }
+}
\ No newline at end of file
index 55f7271e3f914439d8063a6e07f570e0f36834be..d98598cc48f87f5cf24ee27d425a7176ebe98378 100644 (file)
@@ -953,11 +953,9 @@ static void gc_remove_nested_data_from_buffer(zend_refcounted *ref, gc_root_buff
        zval *zv;
 
 tail_call:
-       if (root ||
-           (GC_ADDRESS(GC_INFO(ref)) != 0 &&
-            GC_REF_GET_COLOR(ref) == GC_BLACK)) {
-               GC_TRACE_REF(ref, "removing from buffer");
+       do {
                if (root) {
+                       GC_TRACE_REF(ref, "removing from buffer");
                        if (EXPECTED(GC_ADDRESS(GC_INFO(root->ref)) < GC_ROOT_BUFFER_MAX_ENTRIES)) {
                                gc_remove_from_roots(root);
                        } else {
@@ -965,8 +963,18 @@ tail_call:
                        }
                        GC_INFO(ref) = 0;
                        root = NULL;
-               } else {
+               } else if (GC_ADDRESS(GC_INFO(ref)) != 0
+                && GC_REF_GET_COLOR(ref) == GC_BLACK) {
+                       GC_TRACE_REF(ref, "removing from buffer");
                        GC_REMOVE_FROM_BUFFER(ref);
+               } else if (GC_TYPE(ref) == IS_REFERENCE) {
+                       if (Z_REFCOUNTED(((zend_reference*)ref)->val)) {
+                               ref = Z_COUNTED(((zend_reference*)ref)->val);
+                               goto tail_call;
+                       }
+                       return;
+               } else {
+                       return;
                }
 
                if (GC_TYPE(ref) == IS_OBJECT) {
@@ -1004,12 +1012,6 @@ tail_call:
                        }
                } else if (GC_TYPE(ref) == IS_ARRAY) {
                        ht = (zend_array*)ref;
-               } else if (GC_TYPE(ref) == IS_REFERENCE) {
-                       if (Z_REFCOUNTED(((zend_reference*)ref)->val)) {
-                               ref = Z_COUNTED(((zend_reference*)ref)->val);
-                               goto tail_call;
-                       }
-                       return;
                } else {
                        return;
                }
@@ -1045,7 +1047,7 @@ tail_call:
                }
                ref = Z_COUNTED_P(zv);
                goto tail_call;
-       }
+       } while (0);
 }
 
 ZEND_API int zend_gc_collect_cycles(void)