]> granicus.if.org Git - php/commitdiff
Fixed bug #71818 (Memory leak when array altered in destructor)
authorDmitry Stogov <dmitry@zend.com>
Thu, 14 Jul 2016 09:05:44 +0000 (12:05 +0300)
committerDmitry Stogov <dmitry@zend.com>
Thu, 14 Jul 2016 09:05:44 +0000 (12:05 +0300)
NEWS
Zend/tests/bug71818.phpt [new file with mode: 0644]
Zend/zend_gc.c

diff --git a/NEWS b/NEWS
index 75517885d0d1564513e4a686307157ffd2d5d01b..01dfe0c3f89fca229542dbd6a141a9cb23186e1b 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -13,6 +13,7 @@ PHP                                                                        NEWS
   . Fixed bug #72216 (Return by reference with finally is not memory safe).
     (Dmitry)
   . Fixed bug #72215 (Wrong return value if var modified in finally). (Dmitry)
+  . Fixed bug #71818 (Memory leak when array altered in destructor). (Dmitry)
   . Fixed bug #71539 (Memory error on $arr[$a] =& $arr[$b] if RHS rehashes)
     (Dmitry, Nikita)
   . Added new constant PHP_FD_SETSIZE. (cmb)
diff --git a/Zend/tests/bug71818.phpt b/Zend/tests/bug71818.phpt
new file mode 100644 (file)
index 0000000..5a7bffe
--- /dev/null
@@ -0,0 +1,28 @@
+--TEST--
+Bug #71818 (Memory leak when array altered in destructor)
+--FILE--
+<?php
+class MemoryLeak
+{
+    public function __construct()
+    {
+        $this->things[] = $this;
+    }
+
+    public function __destruct()
+    {
+        $this->things[] = null;
+    }
+
+    private $things = [];
+}
+
+ini_set('memory_limit', '10M');
+
+for ($i = 0; $i < 100000; ++$i) {
+    $obj = new MemoryLeak();
+}
+echo "OK\n";
+?>
+--EXPECT--
+OK
index c001efceadfb07d5db155030fa576a8764a6d645..0e18a497a50367d1b74fef4fff2d5438f6b151cd 100644 (file)
@@ -735,7 +735,6 @@ static void gc_add_garbage(zend_refcounted *ref, gc_additional_buffer **addition
                GC_TYPE(ref) |= GC_FAKE_BUFFER_FLAG;
        }
        if (buf) {
-               GC_REFCOUNT(ref)++;
                buf->ref = ref;
                buf->next = GC_G(roots).next;
                buf->prev = &GC_G(roots);
@@ -898,7 +897,6 @@ static int gc_collect_roots(uint32_t *flags, gc_additional_buffer **additional_b
 
        current = GC_G(roots).next;
        while (current != &GC_G(roots)) {
-               GC_REFCOUNT(current->ref)++;
                if (GC_REF_GET_COLOR(current->ref) == GC_WHITE) {
                        count += gc_collect_white(current->ref, flags, additional_buffer);
                }
@@ -939,7 +937,6 @@ tail_call:
             GC_REF_GET_COLOR(ref) == GC_BLACK &&
             GC_ADDRESS(GC_INFO(ref)) != GC_ROOT_BUFFER_MAX_ENTRIES)) {
                GC_TRACE_REF(ref, "removing from buffer");
-               GC_REFCOUNT(ref)--;
                if (root) {
                        GC_INFO(ref) = 0;
                        GC_REMOVE_FROM_ROOTS(root);