summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorXinchen Hui <laruence@gmail.com>2015-11-03 17:53:56 -0800
committerAnatol Belski <ab@php.net>2015-11-08 02:55:02 +0100
commit46bb5a8cc957f2a12a25b51a90e0975713f75834 (patch)
tree1300c61178d1a7582de93f04c5cac1b39bec38bf
parent20b773438dcbb2da326c93a9af712f65bdfb73b3 (diff)
downloadphp-git-46bb5a8cc957f2a12a25b51a90e0975713f75834.tar.gz
Fixed bug #70805 (Segmentation faults whilst running Drupal 8 test suite)
-rw-r--r--Zend/tests/bug70805.phpt46
-rw-r--r--Zend/tests/bug70805_1.phpt43
-rw-r--r--Zend/tests/bug70805_2.phpt37
-rw-r--r--Zend/zend_gc.c7
-rw-r--r--Zend/zend_hash.c8
-rw-r--r--Zend/zend_vm_def.h10
-rw-r--r--Zend/zend_vm_execute.h90
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);