]> granicus.if.org Git - php/commitdiff
Fixed bug #70805 (Segmentation faults whilst running Drupal 8 test suite)
authorXinchen Hui <laruence@gmail.com>
Wed, 4 Nov 2015 01:53:56 +0000 (17:53 -0800)
committerXinchen Hui <laruence@gmail.com>
Wed, 4 Nov 2015 01:53:56 +0000 (17:53 -0800)
NEWS
Zend/tests/bug70805.phpt [new file with mode: 0644]
Zend/tests/bug70805_1.phpt [new file with mode: 0644]
Zend/tests/bug70805_2.phpt [new file with mode: 0644]
Zend/zend_gc.c
Zend/zend_hash.c
Zend/zend_vm_def.h
Zend/zend_vm_execute.h

diff --git a/NEWS b/NEWS
index d3f01376ce841286d5c56740b1db7730cdd7709c..3a0b71286b57685f9711dbd5d3a3549827446256 100644 (file)
--- 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 (file)
index 0000000..256f52e
--- /dev/null
@@ -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 (file)
index 0000000..0225b4c
--- /dev/null
@@ -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 (file)
index 0000000..a9b1168
--- /dev/null
@@ -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)
index e223a499068b56c663af199c8f2c8b894e986587..74c534844d714456955a93197cb0f443f748f977 100644 (file)
@@ -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
index 8a8ef2948ea35f12393751c0b970f00d9e474bba..52868cf4a6df60d6635662789dd078a2107a4354 100644 (file)
@@ -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);
index ad6dc58ec9b07c1892b1b992efd57746e931f6ea..1fc343b5cb2e514e426c4c5f913366091d30b62a 100644 (file)
@@ -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);
index 97e08b75f9357ba4a05601fc006cbd63e5831c63..dcf0f071f7a6adcb0232049347a65c37d0a64c24 100644 (file)
@@ -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);