Skip to content

Commit

Permalink
Prevent fiber switching in tick function and signal handlers (#9028)
Browse files Browse the repository at this point in the history
  • Loading branch information
trowski committed Jul 16, 2022
1 parent 928624e commit 2bc6025
Show file tree
Hide file tree
Showing 6 changed files with 127 additions and 0 deletions.
37 changes: 37 additions & 0 deletions Zend/tests/fibers/signal-async.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
--TEST--
Prevent switching fibers when async signals are enabled
--EXTENSIONS--
pcntl
posix
--FILE--
<?php

pcntl_async_signals(true);

pcntl_signal(SIGUSR1, function (): void {
if (Fiber::getCurrent() !== null) {
Fiber::suspend();
}
});

$fiber = new Fiber(function (): void {
echo "Fiber start\n";
posix_kill(posix_getpid(), SIGUSR1);
time_nanosleep(1);
echo "Fiber end\n";
});

$fiber->start();

?>
--EXPECTF--
Fiber start

Fatal error: Uncaught FiberError: Cannot switch fibers in current execution context in %ssignal-async.php:%d
Stack trace:
#0 %ssignal-async.php(%d): Fiber::suspend()
#1 %ssignal-async.php(%d): {closure}(%d, Array)
#2 [internal function]: {closure}()
#3 %ssignal-async.php(%d): Fiber->start()
#4 {main}
thrown in %ssignal-async.php on line %d
46 changes: 46 additions & 0 deletions Zend/tests/fibers/signal-dispatch.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
--TEST--
Prevent switching fibers when dispatching pending signals
--EXTENSIONS--
pcntl
posix
--FILE--
<?php

pcntl_signal(SIGUSR1, function (): void {
if (Fiber::getCurrent() !== null) {
Fiber::suspend();
}
});

$fiber = new Fiber(function (): void {
echo "Fiber start\n";

posix_kill(posix_getpid(), SIGUSR1);

try {
pcntl_signal_dispatch();
} catch (FiberError $e) {
Fiber::suspend($e);
}

echo "Fiber end\n";
});

$e = $fiber->start();

echo $e, "\n";

$fiber->resume();

?>
--EXPECTF--
Fiber start
FiberError: Cannot switch fibers in current execution context in %ssignal-dispatch.php:%d
Stack trace:
#0 %ssignal-dispatch.php(%d): Fiber::suspend()
#1 [internal function]: {closure}(%d, Array)
#2 %ssignal-dispatch.php(%d): pcntl_signal_dispatch()
#3 [internal function]: {closure}()
#4 %ssignal-dispatch.php(%d): Fiber->start()
#5 {main}
Fiber end
33 changes: 33 additions & 0 deletions Zend/tests/fibers/ticks.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
--TEST--
Prevent switching fibers in tick function
--FILE--
<?php

declare(ticks=1);

register_tick_function(function (): void {
if (Fiber::getCurrent() !== null) {
Fiber::suspend();
}
});

$fiber = new Fiber(function (): void {
echo "1\n";
echo "2\n";
echo "3\n";
});

$fiber->start();

?>
--EXPECTF--
1

Fatal error: Uncaught FiberError: Cannot switch fibers in current execution context in %sticks.php:%d
Stack trace:
#0 %sticks.php(%d): Fiber::suspend()
#1 %sticks.php(%d): {closure}()
#2 [internal function]: {closure}()
#3 %sticks.php(%d): Fiber->start()
#4 {main}
thrown in %sticks.php on line %d
2 changes: 2 additions & 0 deletions Zend/zend_vm_def.h
Original file line number Diff line number Diff line change
Expand Up @@ -7752,7 +7752,9 @@ ZEND_VM_HANDLER(105, ZEND_TICKS, ANY, ANY, NUM)
EG(ticks_count) = 0;
if (zend_ticks_function) {
SAVE_OPLINE();
zend_fiber_switch_block();
zend_ticks_function(opline->extended_value);
zend_fiber_switch_unblock();
ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION();
}
}
Expand Down
2 changes: 2 additions & 0 deletions Zend/zend_vm_execute.h

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

7 changes: 7 additions & 0 deletions ext/pcntl/pcntl.c
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@
#include "pcntl_arginfo.h"
#include "php_signal.h"
#include "php_ticks.h"
#include "zend_fibers.h"

#if defined(HAVE_GETPRIORITY) || defined(HAVE_SETPRIORITY) || defined(HAVE_WAIT3)
#include <sys/wait.h>
Expand Down Expand Up @@ -1410,6 +1411,9 @@ void pcntl_signal_dispatch()
return;
}

/* Prevent switching fibers when handling signals */
zend_fiber_switch_block();

/* Prevent reentrant handler calls */
PCNTL_G(processing_signal_queue) = 1;

Expand Down Expand Up @@ -1450,6 +1454,9 @@ void pcntl_signal_dispatch()
/* Re-enable queue */
PCNTL_G(processing_signal_queue) = 0;

/* Re-enable fiber switching */
zend_fiber_switch_unblock();

/* return signal mask to previous state */
sigprocmask(SIG_SETMASK, &old_mask, NULL);
}
Expand Down

0 comments on commit 2bc6025

Please sign in to comment.