Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 29 additions & 0 deletions Zend/tests/exception_previous_already_in_chain_destructor.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
--TEST--
Exception thrown in a destructor during unwinding that already has the pending exception in its previous chain
--FILE--
<?php
class ThrowsInDestructor {
public function __construct(private Throwable $pending) {}

public function __destruct() {
throw new LogicException("thrown", 0, $this->pending);
}
}

function f() {
$pending = new RuntimeException("pending");
$object = new ThrowsInDestructor($pending);
throw $pending;
}

try {
f();
} catch (Throwable $t) {
for (; $t !== null; $t = $t->getPrevious()) {
echo $t->getMessage(), "\n";
}
}
?>
--EXPECT--
thrown
pending
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
--TEST--
Exception thrown by a GC destructor that already has the exception of a previous, suspended destructor in its previous chain
--FILE--
<?php
class Cycle {
public static ?Throwable $pending = null;
public $self;

public function __construct() {
$this->self = $this;
}

public function __destruct() {
if (self::$pending === null) {
try {
Fiber::suspend();
} finally {
self::$pending = new RuntimeException("pending");
throw self::$pending;
}
}
throw new LogicException("thrown", 0, self::$pending);
}
}

$fiber = new Fiber(function () {
new Cycle;
new Cycle;
try {
gc_collect_cycles();
} catch (Throwable $t) {
for (; $t !== null; $t = $t->getPrevious()) {
echo $t->getMessage(), "\n";
}
}
});
$fiber->start();
?>
--EXPECT--
thrown
pending
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
--TEST--
Exception thrown in finally of a fiber destroyed during unwinding that already has the pending exception in its previous chain
--FILE--
<?php
function f() {
$pending = new RuntimeException("pending");
$fiber = new Fiber(function () use ($pending) {
try {
Fiber::suspend();
} finally {
throw new LogicException("thrown", 0, $pending);
}
});
$fiber->start();
throw $pending;
}

try {
f();
} catch (Throwable $t) {
for (; $t !== null; $t = $t->getPrevious()) {
echo $t->getMessage(), "\n";
}
}
?>
--EXPECT--
thrown
pending
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
--TEST--
Exception thrown in finally of a generator destroyed during unwinding that already has the pending exception in its previous chain
--FILE--
<?php
function gen(Throwable $pending) {
try {
yield;
} finally {
throw new LogicException("thrown", 0, $pending);
}
}

function f() {
$pending = new RuntimeException("pending");
$generator = gen($pending);
$generator->current();
throw $pending;
}

try {
f();
} catch (Throwable $t) {
for (; $t !== null; $t = $t->getPrevious()) {
echo $t->getMessage(), "\n";
}
}
?>
--EXPECT--
thrown
pending
38 changes: 38 additions & 0 deletions Zend/tests/try/try_finally_previous_already_in_chain.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
--TEST--
Exception thrown in finally that already has the pending exception in its previous chain
--FILE--
<?php
function direct() {
$e = new RuntimeException("pending");
try {
throw $e;
} finally {
throw new LogicException("thrown", 0, $e);
}
}

function nested() {
$e = new RuntimeException("pending");
try {
throw $e;
} finally {
throw new LogicException("thrown", 0, new Exception("middle", 0, $e));
}
}

foreach (['direct', 'nested'] as $function) {
try {
$function();
} catch (Throwable $t) {
for (; $t !== null; $t = $t->getPrevious()) {
echo $t->getMessage(), "\n";
}
}
}
?>
--EXPECT--
thrown
pending
thrown
middle
pending
2 changes: 2 additions & 0 deletions Zend/zend_exceptions.c
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,8 @@ void zend_exception_set_previous(zend_object *exception, zend_object *add_previo
}
ex = previous;
} while (Z_OBJ_P(ex) != add_previous);

OBJ_RELEASE(add_previous);
}
/* }}} */

Expand Down
Loading