Fixed bug #45434 (circular reference causes segfault in gc_collect_cycles())

This commit is contained in:
Dmitry Stogov 2008-07-08 08:16:18 +00:00
parent 8d2e0a7e0f
commit 0ab4c933e7
3 changed files with 28 additions and 11 deletions

View file

@ -1,5 +1,5 @@
--TEST--
GC 028: GC and destructors
GC 029: GC and destructors
--FILE--
<?php
class Foo {

21
Zend/tests/gc_030.phpt Normal file
View file

@ -0,0 +1,21 @@
--TEST--
GC 030: GC and exceptions in destructors
--FILE--
<?php
class foo {
public $foo;
public function __destruct() {
throw new Exception("foobar");
}
}
$f1 = new foo;
$f2 = new foo;
$f1->foo = $f2;
$f2->foo = $f1;
unset($f1, $f2);
gc_collect_cycles();
?>
--EXPECTF--
Fatal error: Ignoring exception from foo::__destruct() while an exception is already active (Uncaught Exception in %sgc_030.php on line %d) in %sgc_030.php on line %d

View file

@ -553,9 +553,9 @@ ZEND_API int gc_collect_cycles(TSRMLS_D)
!EG(objects_store).object_buckets[Z_OBJ_HANDLE(p->z)].destructor_called) {
EG(objects_store).object_buckets[Z_OBJ_HANDLE(p->z)].destructor_called = 1;
zend_try {
EG(objects_store).object_buckets[Z_OBJ_HANDLE(p->z)].bucket.obj.dtor(EG(objects_store).object_buckets[Z_OBJ_HANDLE(p->z)].bucket.obj.object, Z_OBJ_HANDLE(p->z) TSRMLS_CC);
} zend_end_try();
EG(objects_store).object_buckets[Z_OBJ_HANDLE(p->z)].bucket.obj.refcount++;
EG(objects_store).object_buckets[Z_OBJ_HANDLE(p->z)].bucket.obj.dtor(EG(objects_store).object_buckets[Z_OBJ_HANDLE(p->z)].bucket.obj.object, Z_OBJ_HANDLE(p->z) TSRMLS_CC);
EG(objects_store).object_buckets[Z_OBJ_HANDLE(p->z)].bucket.obj.refcount--;
}
}
count++;
@ -571,19 +571,15 @@ ZEND_API int gc_collect_cycles(TSRMLS_D)
EG(objects_store).object_buckets[Z_OBJ_HANDLE(p->z)].valid &&
EG(objects_store).object_buckets[Z_OBJ_HANDLE(p->z)].bucket.obj.refcount <= 0) {
EG(objects_store).object_buckets[Z_OBJ_HANDLE(p->z)].bucket.obj.refcount = 1;
zend_try {
Z_TYPE(p->z) = IS_NULL;
zend_objects_store_del_ref_by_handle(Z_OBJ_HANDLE(p->z) TSRMLS_CC);
} zend_end_try();
Z_TYPE(p->z) = IS_NULL;
zend_objects_store_del_ref_by_handle(Z_OBJ_HANDLE(p->z) TSRMLS_CC);
}
} else if (Z_TYPE(p->z) == IS_ARRAY) {
Z_TYPE(p->z) = IS_NULL;
zend_hash_destroy(Z_ARRVAL(p->z));
FREE_HASHTABLE(Z_ARRVAL(p->z));
} else {
zend_try {
zval_dtor(&p->z);
} zend_end_try();
zval_dtor(&p->z);
Z_TYPE(p->z) = IS_NULL;
}
p = GC_G(next_to_free);