Skip to content

Commit

Permalink
Partially fix handling of exceptions thrown in interrupt handlers
Browse files Browse the repository at this point in the history
  • Loading branch information
dstogov committed Nov 11, 2021
1 parent 8c4a7f2 commit fa0b84a
Show file tree
Hide file tree
Showing 5 changed files with 109 additions and 0 deletions.
14 changes: 14 additions & 0 deletions Zend/zend_vm_def.h
Original file line number Diff line number Diff line change
Expand Up @@ -9680,6 +9680,20 @@ ZEND_VM_HELPER(zend_interrupt_helper, ANY, ANY)
zend_timeout();
} else if (zend_interrupt_function) {
zend_interrupt_function(execute_data);
if (EG(exception)) {
/* We have to UNDEF result, because ZEND_HANDLE_EXCEPTION is going to free it */
const zend_op *throw_op = EG(opline_before_exception);

if (throw_op
&& throw_op->result_type & (IS_TMP_VAR|IS_VAR)
&& throw_op->opcode != ZEND_ADD_ARRAY_ELEMENT
&& throw_op->opcode != ZEND_ADD_ARRAY_UNPACK
&& throw_op->opcode != ZEND_ROPE_INIT
&& throw_op->opcode != ZEND_ROPE_ADD) {
ZVAL_UNDEF(ZEND_CALL_VAR(EG(current_execute_data), throw_op->result.var));

}
}
ZEND_VM_ENTER();
}
ZEND_VM_CONTINUE();
Expand Down
14 changes: 14 additions & 0 deletions Zend/zend_vm_execute.h
Original file line number Diff line number Diff line change
Expand Up @@ -3384,6 +3384,20 @@ static zend_never_inline ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL zend_interrupt_he
zend_timeout();
} else if (zend_interrupt_function) {
zend_interrupt_function(execute_data);
if (EG(exception)) {
/* We have to UNDEF result, because ZEND_HANDLE_EXCEPTION is going to free it */
const zend_op *throw_op = EG(opline_before_exception);

if (throw_op
&& throw_op->result_type & (IS_TMP_VAR|IS_VAR)
&& throw_op->opcode != ZEND_ADD_ARRAY_ELEMENT
&& throw_op->opcode != ZEND_ADD_ARRAY_UNPACK
&& throw_op->opcode != ZEND_ROPE_INIT
&& throw_op->opcode != ZEND_ROPE_ADD) {
ZVAL_UNDEF(ZEND_CALL_VAR(EG(current_execute_data), throw_op->result.var));

}
}
ZEND_VM_ENTER();
}
ZEND_VM_CONTINUE();
Expand Down
33 changes: 33 additions & 0 deletions ext/pcntl/tests/bug81577.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
--TEST--
Bug #81577: (Exceptions in interrupt handlers)
--SKIPIF--
<?php
if (!extension_loaded("pcntl")) print "skip pcntl extension not available";
elseif (!extension_loaded('posix')) die('skip posix extension not available');
?>
--FILE--
<?php
class C {
public static $cond = 1;
public static $a;
}

C::$a = [ C::$cond ]; // make countable zval

pcntl_async_signals(true);
pcntl_signal(SIGTERM, function ($signo) { throw new Exception("Signal"); });
for ($i = 0; $i < 5; $i++) {
try {
C::$a + C::$a;
posix_kill(posix_getpid(), SIGTERM) + C::$cond;
} catch (Throwable $ex) {
echo get_class($ex) , " : " , $ex->getMessage() , "\n";
}
}
?>
--EXPECT--
Exception : Signal
Exception : Signal
Exception : Signal
Exception : Signal
Exception : Signal
27 changes: 27 additions & 0 deletions ext/pcntl/tests/bug81577_2.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
--TEST--
Bug #81577: (Exceptions in interrupt handlers: ADD_ARRAY_ELEMENT)
--SKIPIF--
<?php
if (!extension_loaded("pcntl")) print "skip pcntl extension not available";
elseif (!extension_loaded('posix')) die('skip posix extension not available');
?>
--FILE--
<?php
pcntl_async_signals(true);
pcntl_signal(SIGTERM, function ($signo) {});
try {
$a = [1, posix_kill(posix_getpid(), SIGTERM), 2];
} catch (Throwable $ex) {
echo get_class($ex) , " : " , $ex->getMessage() , "\n";
}
var_dump($a);
?>
--EXPECT--
array(3) {
[0]=>
int(1)
[1]=>
bool(true)
[2]=>
int(2)
}
21 changes: 21 additions & 0 deletions ext/pcntl/tests/bug81577_3.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
--TEST--
Bug #81577: (Exceptions in interrupt handlers: cleanup_live_vars)
--SKIPIF--
<?php
if (!extension_loaded("pcntl")) print "skip pcntl extension not available";
elseif (!extension_loaded('posix')) die('skip posix extension not available');
?>
--XFAIL--
leaks are not fixed yet
--FILE--
<?php
pcntl_async_signals(true);
pcntl_signal(SIGTERM, function ($signo) { throw new Exception("Signal"); });
try {
array_merge([1], [2]) + posix_kill(posix_getpid(), SIGTERM);
} catch (Throwable $ex) {
echo get_class($ex) , " : " , $ex->getMessage() , "\n";
}
?>
--EXPECT--
Exception : Signal

0 comments on commit fa0b84a

Please sign in to comment.