diff options
author | Dmitry Stogov <dmitry@zend.com> | 2019-08-09 17:43:50 +0300 |
---|---|---|
committer | Dmitry Stogov <dmitry@zend.com> | 2019-08-09 17:43:50 +0300 |
commit | 9b43e29d9b55eafb4e063a0b2d817356f5b908b5 (patch) | |
tree | bcde7c9bd1a5918a941828afcb5c477a9d9f268e | |
parent | 6b1cc1252e73e51e53194c8c65e3d2302bc83dca (diff) | |
download | php-git-9b43e29d9b55eafb4e063a0b2d817356f5b908b5.tar.gz |
Fixed handling of references in nested data of objects with destructor
-rw-r--r-- | Zend/tests/gc_041.phpt | 35 | ||||
-rw-r--r-- | Zend/zend_gc.c | 26 |
2 files changed, 49 insertions, 12 deletions
diff --git a/Zend/tests/gc_041.phpt b/Zend/tests/gc_041.phpt new file mode 100644 index 0000000000..7400e23756 --- /dev/null +++ b/Zend/tests/gc_041.phpt @@ -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 diff --git a/Zend/zend_gc.c b/Zend/zend_gc.c index 55f7271e3f..d98598cc48 100644 --- a/Zend/zend_gc.c +++ b/Zend/zend_gc.c @@ -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) |