Prevent fiber switching in tick function and signal handlers (#9028)

This commit is contained in:
Aaron Piotrowski 2022-07-16 13:05:16 -05:00 committed by GitHub
parent 928624ed8a
commit 2bc6025c2c
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
6 changed files with 127 additions and 0 deletions

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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();
}
}

View file

@ -2996,7 +2996,9 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_TICKS_SPEC_HANDLER(ZEND_OPCODE
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();
}
}

View file

@ -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>
@ -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;
@ -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);
}