From 2f2653aa7758cd586f1daff288146740dd5fa61b Mon Sep 17 00:00:00 2001 From: Xinchen Hui Date: Tue, 3 Nov 2015 17:53:56 -0800 Subject: [PATCH] Fixed bug #70805 (Segmentation faults whilst running Drupal 8 test suite) --- NEWS | 4 ++ Zend/tests/bug70805.phpt | 46 +++++++++++++++++++ Zend/tests/bug70805_1.phpt | 43 ++++++++++++++++++ Zend/tests/bug70805_2.phpt | 37 ++++++++++++++++ Zend/zend_gc.c | 7 +++ Zend/zend_hash.c | 8 +++- Zend/zend_vm_def.h | 10 ++++- Zend/zend_vm_execute.h | 90 ++++++++++++++++++++++++++++++-------- 8 files changed, 223 insertions(+), 22 deletions(-) create mode 100644 Zend/tests/bug70805.phpt create mode 100644 Zend/tests/bug70805_1.phpt create mode 100644 Zend/tests/bug70805_2.phpt diff --git a/NEWS b/NEWS index d3f01376ce..3a0b71286b 100644 --- a/NEWS +++ b/NEWS @@ -2,6 +2,10 @@ PHP NEWS ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||| ?? ??? 2015, PHP 7.0.1 +- Core: + . Fixed bug #70805 (Segmentation faults whilst running Drupal 8 test suite). + (Dmitry, Laruence) + - Opcache: . Fixed bug #70656 (require() statement broken after opcache_reset() or a few hours of use). (Laruence) diff --git a/Zend/tests/bug70805.phpt b/Zend/tests/bug70805.phpt new file mode 100644 index 0000000000..256f52eed5 --- /dev/null +++ b/Zend/tests/bug70805.phpt @@ -0,0 +1,46 @@ +--TEST-- +Bug #70805 (Segmentation faults whilst running Drupal 8 test suite) +--FILE-- +b = new B; +$a->b->a = $a; + +$i = 0; + +$c = new A; +$array = array($c); //This is used to leave a room for $GLOBALS["a"] +unset($c); + +while ($i++ < 9997) { + $t = []; + $t[] = &$t; + unset($t); +} +$t = [new C]; +$t[] = &$t; +unset($t); // This is used to trigger C::__destruct while doing gc_colloct_roots + +$e = $a; +unset($a); // This one can not be putted into roots buf because it's full, thus gc_colloct_roots will be called, + // but C::__destructor which is called in gc_colloct_roots will put $a into buf + // which will make $a be putted into gc roots buf twice +var_dump(gc_collect_cycles()); +?> +--EXPECT-- +int(0) diff --git a/Zend/tests/bug70805_1.phpt b/Zend/tests/bug70805_1.phpt new file mode 100644 index 0000000000..0225b4ce82 --- /dev/null +++ b/Zend/tests/bug70805_1.phpt @@ -0,0 +1,43 @@ +--TEST-- +Bug #70805 (Segmentation faults whilst running Drupal 8 test suite) (Crash) +--FILE-- +b = new B; +$a->b->a = $a; + +$i = 0; + +$c = new A; +$array = array($c); +unset($c); + +while ($i++ < 9997) { + $t = []; + $t[] = &$t; + unset($t); +} +$t = [new C]; +$t[] = &$t; +unset($t); +unset($a); + +var_dump(gc_collect_cycles()); +?> +--EXPECT-- +int(2) diff --git a/Zend/tests/bug70805_2.phpt b/Zend/tests/bug70805_2.phpt new file mode 100644 index 0000000000..a9b11684f5 --- /dev/null +++ b/Zend/tests/bug70805_2.phpt @@ -0,0 +1,37 @@ +--TEST-- +Bug #70805 (Segmentation faults whilst running Drupal 8 test suite) (Memleak) +--FILE-- +b = new B; +$a->b->a = $a; + +$i = 0; + +while ($i++ < 9998) { + $t = []; + $t[] = &$t; + unset($t); +} +$t = [new C]; +$t[] = &$t; +unset($t); + +unset($a); +var_dump(gc_collect_cycles()); +--EXPECT-- +int(2) diff --git a/Zend/zend_gc.c b/Zend/zend_gc.c index e223a49906..74c534844d 100644 --- a/Zend/zend_gc.c +++ b/Zend/zend_gc.c @@ -242,6 +242,13 @@ ZEND_API void ZEND_FASTCALL gc_possible_root(zend_refcounted *ref) GC_REFCOUNT(ref)++; gc_collect_cycles(); GC_REFCOUNT(ref)--; + if (UNEXPECTED(GC_REFCOUNT(ref)) == 0) { + zval_dtor_func_for_ptr(ref); + return; + } + if (UNEXPECTED(GC_INFO(ref))) { + return; + } newRoot = GC_G(unused); if (!newRoot) { #if ZEND_GC_DEBUG diff --git a/Zend/zend_hash.c b/Zend/zend_hash.c index 8a8ef2948e..52868cf4a6 100644 --- a/Zend/zend_hash.c +++ b/Zend/zend_hash.c @@ -1049,9 +1049,13 @@ ZEND_API int ZEND_FASTCALL zend_hash_del_ind(HashTable *ht, zend_string *key) return FAILURE; } else { if (ht->pDestructor) { - ht->pDestructor(data); + zval tmp; + ZVAL_COPY_VALUE(&tmp, data); + ZVAL_UNDEF(data); + ht->pDestructor(&tmp); + } else { + ZVAL_UNDEF(data); } - ZVAL_UNDEF(data); } } else { _zend_hash_del_el_ex(ht, idx, p, prev); diff --git a/Zend/zend_vm_def.h b/Zend/zend_vm_def.h index ad6dc58ec9..1fc343b5cb 100644 --- a/Zend/zend_vm_def.h +++ b/Zend/zend_vm_def.h @@ -5513,8 +5513,14 @@ ZEND_VM_HANDLER(74, ZEND_UNSET_VAR, CONST|TMPVAR|CV, UNUSED|CONST|VAR) ZVAL_UNDEF(var); zval_dtor_func_for_ptr(garbage); } else { - GC_ZVAL_CHECK_POSSIBLE_ROOT(var); - ZVAL_UNDEF(var); + zval *z = var; + ZVAL_DEREF(z); + if (Z_COLLECTABLE_P(z) && UNEXPECTED(!Z_GC_INFO_P(z))) { + ZVAL_UNDEF(var); + gc_possible_root(Z_COUNTED_P(z)); + } else { + ZVAL_UNDEF(var); + } } } else { ZVAL_UNDEF(var); diff --git a/Zend/zend_vm_execute.h b/Zend/zend_vm_execute.h index 97e08b75f9..dcf0f071f7 100644 --- a/Zend/zend_vm_execute.h +++ b/Zend/zend_vm_execute.h @@ -6105,8 +6105,14 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_UNSET_VAR_SPEC_CONST_CONST_HAN ZVAL_UNDEF(var); zval_dtor_func_for_ptr(garbage); } else { - GC_ZVAL_CHECK_POSSIBLE_ROOT(var); - ZVAL_UNDEF(var); + zval *z = var; + ZVAL_DEREF(z); + if (Z_COLLECTABLE_P(z) && UNEXPECTED(!Z_GC_INFO_P(z))) { + ZVAL_UNDEF(var); + gc_possible_root(Z_COUNTED_P(z)); + } else { + ZVAL_UNDEF(var); + } } } else { ZVAL_UNDEF(var); @@ -7034,8 +7040,14 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_UNSET_VAR_SPEC_CONST_VAR_HANDL ZVAL_UNDEF(var); zval_dtor_func_for_ptr(garbage); } else { - GC_ZVAL_CHECK_POSSIBLE_ROOT(var); - ZVAL_UNDEF(var); + zval *z = var; + ZVAL_DEREF(z); + if (Z_COLLECTABLE_P(z) && UNEXPECTED(!Z_GC_INFO_P(z))) { + ZVAL_UNDEF(var); + gc_possible_root(Z_COUNTED_P(z)); + } else { + ZVAL_UNDEF(var); + } } } else { ZVAL_UNDEF(var); @@ -7894,8 +7906,14 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_UNSET_VAR_SPEC_CONST_UNUSED_HA ZVAL_UNDEF(var); zval_dtor_func_for_ptr(garbage); } else { - GC_ZVAL_CHECK_POSSIBLE_ROOT(var); - ZVAL_UNDEF(var); + zval *z = var; + ZVAL_DEREF(z); + if (Z_COLLECTABLE_P(z) && UNEXPECTED(!Z_GC_INFO_P(z))) { + ZVAL_UNDEF(var); + gc_possible_root(Z_COUNTED_P(z)); + } else { + ZVAL_UNDEF(var); + } } } else { ZVAL_UNDEF(var); @@ -32128,8 +32146,14 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_UNSET_VAR_SPEC_CV_CONST_HANDLE ZVAL_UNDEF(var); zval_dtor_func_for_ptr(garbage); } else { - GC_ZVAL_CHECK_POSSIBLE_ROOT(var); - ZVAL_UNDEF(var); + zval *z = var; + ZVAL_DEREF(z); + if (Z_COLLECTABLE_P(z) && UNEXPECTED(!Z_GC_INFO_P(z))) { + ZVAL_UNDEF(var); + gc_possible_root(Z_COUNTED_P(z)); + } else { + ZVAL_UNDEF(var); + } } } else { ZVAL_UNDEF(var); @@ -33412,8 +33436,14 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_UNSET_VAR_SPEC_CV_VAR_HANDLER( ZVAL_UNDEF(var); zval_dtor_func_for_ptr(garbage); } else { - GC_ZVAL_CHECK_POSSIBLE_ROOT(var); - ZVAL_UNDEF(var); + zval *z = var; + ZVAL_DEREF(z); + if (Z_COLLECTABLE_P(z) && UNEXPECTED(!Z_GC_INFO_P(z))) { + ZVAL_UNDEF(var); + gc_possible_root(Z_COUNTED_P(z)); + } else { + ZVAL_UNDEF(var); + } } } else { ZVAL_UNDEF(var); @@ -34642,8 +34672,14 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_UNSET_VAR_SPEC_CV_UNUSED_HANDL ZVAL_UNDEF(var); zval_dtor_func_for_ptr(garbage); } else { - GC_ZVAL_CHECK_POSSIBLE_ROOT(var); - ZVAL_UNDEF(var); + zval *z = var; + ZVAL_DEREF(z); + if (Z_COLLECTABLE_P(z) && UNEXPECTED(!Z_GC_INFO_P(z))) { + ZVAL_UNDEF(var); + gc_possible_root(Z_COUNTED_P(z)); + } else { + ZVAL_UNDEF(var); + } } } else { ZVAL_UNDEF(var); @@ -41847,8 +41883,14 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_UNSET_VAR_SPEC_TMPVAR_CONST_HA ZVAL_UNDEF(var); zval_dtor_func_for_ptr(garbage); } else { - GC_ZVAL_CHECK_POSSIBLE_ROOT(var); - ZVAL_UNDEF(var); + zval *z = var; + ZVAL_DEREF(z); + if (Z_COLLECTABLE_P(z) && UNEXPECTED(!Z_GC_INFO_P(z))) { + ZVAL_UNDEF(var); + gc_possible_root(Z_COUNTED_P(z)); + } else { + ZVAL_UNDEF(var); + } } } else { ZVAL_UNDEF(var); @@ -42432,8 +42474,14 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_UNSET_VAR_SPEC_TMPVAR_VAR_HAND ZVAL_UNDEF(var); zval_dtor_func_for_ptr(garbage); } else { - GC_ZVAL_CHECK_POSSIBLE_ROOT(var); - ZVAL_UNDEF(var); + zval *z = var; + ZVAL_DEREF(z); + if (Z_COLLECTABLE_P(z) && UNEXPECTED(!Z_GC_INFO_P(z))) { + ZVAL_UNDEF(var); + gc_possible_root(Z_COUNTED_P(z)); + } else { + ZVAL_UNDEF(var); + } } } else { ZVAL_UNDEF(var); @@ -42834,8 +42882,14 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_UNSET_VAR_SPEC_TMPVAR_UNUSED_H ZVAL_UNDEF(var); zval_dtor_func_for_ptr(garbage); } else { - GC_ZVAL_CHECK_POSSIBLE_ROOT(var); - ZVAL_UNDEF(var); + zval *z = var; + ZVAL_DEREF(z); + if (Z_COLLECTABLE_P(z) && UNEXPECTED(!Z_GC_INFO_P(z))) { + ZVAL_UNDEF(var); + gc_possible_root(Z_COUNTED_P(z)); + } else { + ZVAL_UNDEF(var); + } } } else { ZVAL_UNDEF(var); -- 2.50.1