diff options
| author | Xinchen Hui <laruence@gmail.com> | 2015-11-03 17:53:56 -0800 |
|---|---|---|
| committer | Anatol Belski <ab@php.net> | 2015-11-08 02:55:02 +0100 |
| commit | 46bb5a8cc957f2a12a25b51a90e0975713f75834 (patch) | |
| tree | 1300c61178d1a7582de93f04c5cac1b39bec38bf | |
| parent | 20b773438dcbb2da326c93a9af712f65bdfb73b3 (diff) | |
| download | php-git-46bb5a8cc957f2a12a25b51a90e0975713f75834.tar.gz | |
Fixed bug #70805 (Segmentation faults whilst running Drupal 8 test suite)
| -rw-r--r-- | Zend/tests/bug70805.phpt | 46 | ||||
| -rw-r--r-- | Zend/tests/bug70805_1.phpt | 43 | ||||
| -rw-r--r-- | Zend/tests/bug70805_2.phpt | 37 | ||||
| -rw-r--r-- | Zend/zend_gc.c | 7 | ||||
| -rw-r--r-- | Zend/zend_hash.c | 8 | ||||
| -rw-r--r-- | Zend/zend_vm_def.h | 10 | ||||
| -rw-r--r-- | Zend/zend_vm_execute.h | 90 |
7 files changed, 219 insertions, 22 deletions
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-- +<?php +class A { +} + +class B { +} + +class C { + public function __destruct() { + if (isset($GLOBALS["a"])) { + unset($GLOBALS["array"]); + unset($GLOBALS["a"]); // this will be called in gc_colloct_roots and put $a into gc roots buf + } + } +} + +$a = new A; +$a->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-- +<?php +class A { +} + +class B { +} + +class C { + public function __destruct() { + if (isset($GLOBALS["a"])) { + unset($GLOBALS["array"]); + unset($GLOBALS["a"]); + } + } +} + +$a = new A; +$a->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-- +<?php +class A { +} + +class B { +} + +class C { + public function __destruct() { + if (isset($GLOBALS["a"])) { + unset($GLOBALS["a"]); + } + } +} + +$a = new A; +$a->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); |
