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-- --TEST--
GC 028: GC and destructors GC 029: GC and destructors
--FILE-- --FILE--
<?php <?php
class Foo { 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) {
EG(objects_store).object_buckets[Z_OBJ_HANDLE(p->z)].destructor_called = 1; 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.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.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--;
} }
} }
count++; 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)].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 <= 0) {
EG(objects_store).object_buckets[Z_OBJ_HANDLE(p->z)].bucket.obj.refcount = 1; EG(objects_store).object_buckets[Z_OBJ_HANDLE(p->z)].bucket.obj.refcount = 1;
zend_try { Z_TYPE(p->z) = IS_NULL;
Z_TYPE(p->z) = IS_NULL; zend_objects_store_del_ref_by_handle(Z_OBJ_HANDLE(p->z) TSRMLS_CC);
zend_objects_store_del_ref_by_handle(Z_OBJ_HANDLE(p->z) TSRMLS_CC);
} zend_end_try();
} }
} else if (Z_TYPE(p->z) == IS_ARRAY) { } else if (Z_TYPE(p->z) == IS_ARRAY) {
Z_TYPE(p->z) = IS_NULL; Z_TYPE(p->z) = IS_NULL;
zend_hash_destroy(Z_ARRVAL(p->z)); zend_hash_destroy(Z_ARRVAL(p->z));
FREE_HASHTABLE(Z_ARRVAL(p->z)); FREE_HASHTABLE(Z_ARRVAL(p->z));
} else { } else {
zend_try { zval_dtor(&p->z);
zval_dtor(&p->z);
} zend_end_try();
Z_TYPE(p->z) = IS_NULL; Z_TYPE(p->z) = IS_NULL;
} }
p = GC_G(next_to_free); p = GC_G(next_to_free);