Skip to content

Commit fa0b84a

Browse files
committed
Partially fix handling of exceptions thrown in interrupt handlers
1 parent 8c4a7f2 commit fa0b84a

File tree

5 files changed

+109
-0
lines changed

5 files changed

+109
-0
lines changed

Zend/zend_vm_def.h

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9680,6 +9680,20 @@ ZEND_VM_HELPER(zend_interrupt_helper, ANY, ANY)
96809680
zend_timeout();
96819681
} else if (zend_interrupt_function) {
96829682
zend_interrupt_function(execute_data);
9683+
if (EG(exception)) {
9684+
/* We have to UNDEF result, because ZEND_HANDLE_EXCEPTION is going to free it */
9685+
const zend_op *throw_op = EG(opline_before_exception);
9686+
9687+
if (throw_op
9688+
&& throw_op->result_type & (IS_TMP_VAR|IS_VAR)
9689+
&& throw_op->opcode != ZEND_ADD_ARRAY_ELEMENT
9690+
&& throw_op->opcode != ZEND_ADD_ARRAY_UNPACK
9691+
&& throw_op->opcode != ZEND_ROPE_INIT
9692+
&& throw_op->opcode != ZEND_ROPE_ADD) {
9693+
ZVAL_UNDEF(ZEND_CALL_VAR(EG(current_execute_data), throw_op->result.var));
9694+
9695+
}
9696+
}
96839697
ZEND_VM_ENTER();
96849698
}
96859699
ZEND_VM_CONTINUE();

Zend/zend_vm_execute.h

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3384,6 +3384,20 @@ static zend_never_inline ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL zend_interrupt_he
33843384
zend_timeout();
33853385
} else if (zend_interrupt_function) {
33863386
zend_interrupt_function(execute_data);
3387+
if (EG(exception)) {
3388+
/* We have to UNDEF result, because ZEND_HANDLE_EXCEPTION is going to free it */
3389+
const zend_op *throw_op = EG(opline_before_exception);
3390+
3391+
if (throw_op
3392+
&& throw_op->result_type & (IS_TMP_VAR|IS_VAR)
3393+
&& throw_op->opcode != ZEND_ADD_ARRAY_ELEMENT
3394+
&& throw_op->opcode != ZEND_ADD_ARRAY_UNPACK
3395+
&& throw_op->opcode != ZEND_ROPE_INIT
3396+
&& throw_op->opcode != ZEND_ROPE_ADD) {
3397+
ZVAL_UNDEF(ZEND_CALL_VAR(EG(current_execute_data), throw_op->result.var));
3398+
3399+
}
3400+
}
33873401
ZEND_VM_ENTER();
33883402
}
33893403
ZEND_VM_CONTINUE();

ext/pcntl/tests/bug81577.phpt

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
--TEST--
2+
Bug #81577: (Exceptions in interrupt handlers)
3+
--SKIPIF--
4+
<?php
5+
if (!extension_loaded("pcntl")) print "skip pcntl extension not available";
6+
elseif (!extension_loaded('posix')) die('skip posix extension not available');
7+
?>
8+
--FILE--
9+
<?php
10+
class C {
11+
public static $cond = 1;
12+
public static $a;
13+
}
14+
15+
C::$a = [ C::$cond ]; // make countable zval
16+
17+
pcntl_async_signals(true);
18+
pcntl_signal(SIGTERM, function ($signo) { throw new Exception("Signal"); });
19+
for ($i = 0; $i < 5; $i++) {
20+
try {
21+
C::$a + C::$a;
22+
posix_kill(posix_getpid(), SIGTERM) + C::$cond;
23+
} catch (Throwable $ex) {
24+
echo get_class($ex) , " : " , $ex->getMessage() , "\n";
25+
}
26+
}
27+
?>
28+
--EXPECT--
29+
Exception : Signal
30+
Exception : Signal
31+
Exception : Signal
32+
Exception : Signal
33+
Exception : Signal

ext/pcntl/tests/bug81577_2.phpt

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
--TEST--
2+
Bug #81577: (Exceptions in interrupt handlers: ADD_ARRAY_ELEMENT)
3+
--SKIPIF--
4+
<?php
5+
if (!extension_loaded("pcntl")) print "skip pcntl extension not available";
6+
elseif (!extension_loaded('posix')) die('skip posix extension not available');
7+
?>
8+
--FILE--
9+
<?php
10+
pcntl_async_signals(true);
11+
pcntl_signal(SIGTERM, function ($signo) {});
12+
try {
13+
$a = [1, posix_kill(posix_getpid(), SIGTERM), 2];
14+
} catch (Throwable $ex) {
15+
echo get_class($ex) , " : " , $ex->getMessage() , "\n";
16+
}
17+
var_dump($a);
18+
?>
19+
--EXPECT--
20+
array(3) {
21+
[0]=>
22+
int(1)
23+
[1]=>
24+
bool(true)
25+
[2]=>
26+
int(2)
27+
}

ext/pcntl/tests/bug81577_3.phpt

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
--TEST--
2+
Bug #81577: (Exceptions in interrupt handlers: cleanup_live_vars)
3+
--SKIPIF--
4+
<?php
5+
if (!extension_loaded("pcntl")) print "skip pcntl extension not available";
6+
elseif (!extension_loaded('posix')) die('skip posix extension not available');
7+
?>
8+
--XFAIL--
9+
leaks are not fixed yet
10+
--FILE--
11+
<?php
12+
pcntl_async_signals(true);
13+
pcntl_signal(SIGTERM, function ($signo) { throw new Exception("Signal"); });
14+
try {
15+
array_merge([1], [2]) + posix_kill(posix_getpid(), SIGTERM);
16+
} catch (Throwable $ex) {
17+
echo get_class($ex) , " : " , $ex->getMessage() , "\n";
18+
}
19+
?>
20+
--EXPECT--
21+
Exception : Signal

0 commit comments

Comments
 (0)