From 00445ba22dd97988009692e2b35edaeff715f5e1 Mon Sep 17 00:00:00 2001 From: Dmitry Stogov Date: Tue, 14 Apr 2015 19:53:56 +0300 Subject: [PATCH] Fixed bug #69446 (GC leak relating to removal of nested data after dtors run) --- Zend/tests/bug64896.phpt | 1 + Zend/tests/bug69446.phpt | 30 ++++++++++++++++++++++++++++++ Zend/tests/bug69446_2.phpt | 38 ++++++++++++++++++++++++++++++++++++++ Zend/zend_gc.c | 3 +-- 4 files changed, 70 insertions(+), 2 deletions(-) create mode 100644 Zend/tests/bug69446.phpt create mode 100644 Zend/tests/bug69446_2.phpt diff --git a/Zend/tests/bug64896.phpt b/Zend/tests/bug64896.phpt index f01969782f..3ff4a2167d 100644 --- a/Zend/tests/bug64896.phpt +++ b/Zend/tests/bug64896.phpt @@ -30,6 +30,7 @@ gc_disable(); unserialize(serialize($foo)); gc_collect_cycles(); var_dump($bar); +gc_enable(); /* will output: object(bad)#4 (1) { ["_private":"bad":private]=> diff --git a/Zend/tests/bug69446.phpt b/Zend/tests/bug69446.phpt new file mode 100644 index 0000000000..b448a2be7d --- /dev/null +++ b/Zend/tests/bug69446.phpt @@ -0,0 +1,30 @@ +--TEST-- +Bug #69446 (GC leak relating to removal of nested data after dtors run) +--FILE-- +y = new stdClass; + } +} + +$foo = new stdClass; +$foo->foo = $foo; +$foo->bad = new bad; +$foo->bad->x = new stdClass; + +unset($foo); +gc_collect_cycles(); +var_dump($bar); +--EXPECT-- +object(bad)#2 (2) { + ["x"]=> + object(stdClass)#3 (0) { + } + ["y"]=> + object(stdClass)#4 (0) { + } +} diff --git a/Zend/tests/bug69446_2.phpt b/Zend/tests/bug69446_2.phpt new file mode 100644 index 0000000000..520bd1fe30 --- /dev/null +++ b/Zend/tests/bug69446_2.phpt @@ -0,0 +1,38 @@ +--TEST-- +Bug #69446 (GC leak relating to removal of nested data after dtors run) +--FILE-- +_private[] = 'php'; + } + + public function __destruct() + { + global $bar; + $bar = $this; + } +} + +$foo = new stdclass; +$foo->foo = $foo; +$foo->bad = new bad; + +unserialize(serialize($foo)); +//unset($foo); + +gc_collect_cycles(); +var_dump($bar); +--EXPECT-- +object(bad)#4 (1) { + ["_private"]=> + array(1) { + [0]=> + string(3) "php" + } +} diff --git a/Zend/zend_gc.c b/Zend/zend_gc.c index 8669db17b6..d5c8ea8adc 100644 --- a/Zend/zend_gc.c +++ b/Zend/zend_gc.c @@ -720,7 +720,6 @@ static int gc_collect_roots(uint32_t *flags) current = GC_G(roots).next; while (current != &GC_G(roots)) { if (GC_REF_GET_COLOR(current->ref) == GC_WHITE) { - GC_REFCOUNT(current->ref)++; count += gc_collect_white(current->ref, flags); } current = current->next; @@ -832,7 +831,7 @@ static void gc_remove_nested_data_from_buffer(zend_refcounted *ref) Bucket *p, *end; tail_call: - if (GC_ADDRESS(GC_INFO(ref)) != 0) { + 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); -- 2.40.0