From 2bc6025c2cb2d17879fef55f91236088c6cb34e5 Mon Sep 17 00:00:00 2001 From: Aaron Piotrowski Date: Sat, 16 Jul 2022 13:05:16 -0500 Subject: [PATCH] Prevent fiber switching in tick function and signal handlers (#9028) --- Zend/tests/fibers/signal-async.phpt | 37 +++++++++++++++++++++ Zend/tests/fibers/signal-dispatch.phpt | 46 ++++++++++++++++++++++++++ Zend/tests/fibers/ticks.phpt | 33 ++++++++++++++++++ Zend/zend_vm_def.h | 2 ++ Zend/zend_vm_execute.h | 2 ++ ext/pcntl/pcntl.c | 7 ++++ 6 files changed, 127 insertions(+) create mode 100644 Zend/tests/fibers/signal-async.phpt create mode 100644 Zend/tests/fibers/signal-dispatch.phpt create mode 100644 Zend/tests/fibers/ticks.phpt diff --git a/Zend/tests/fibers/signal-async.phpt b/Zend/tests/fibers/signal-async.phpt new file mode 100644 index 00000000000..f1f5a2f4c8f --- /dev/null +++ b/Zend/tests/fibers/signal-async.phpt @@ -0,0 +1,37 @@ +--TEST-- +Prevent switching fibers when async signals are enabled +--EXTENSIONS-- +pcntl +posix +--FILE-- +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 diff --git a/Zend/tests/fibers/signal-dispatch.phpt b/Zend/tests/fibers/signal-dispatch.phpt new file mode 100644 index 00000000000..abde8e313d7 --- /dev/null +++ b/Zend/tests/fibers/signal-dispatch.phpt @@ -0,0 +1,46 @@ +--TEST-- +Prevent switching fibers when dispatching pending signals +--EXTENSIONS-- +pcntl +posix +--FILE-- +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 diff --git a/Zend/tests/fibers/ticks.phpt b/Zend/tests/fibers/ticks.phpt new file mode 100644 index 00000000000..fbd050c09b9 --- /dev/null +++ b/Zend/tests/fibers/ticks.phpt @@ -0,0 +1,33 @@ +--TEST-- +Prevent switching fibers in tick function +--FILE-- +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 diff --git a/Zend/zend_vm_def.h b/Zend/zend_vm_def.h index 9043cde725b..86557b6e2bf 100644 --- a/Zend/zend_vm_def.h +++ b/Zend/zend_vm_def.h @@ -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(); } } diff --git a/Zend/zend_vm_execute.h b/Zend/zend_vm_execute.h index 39005c91849..13ba7443360 100644 --- a/Zend/zend_vm_execute.h +++ b/Zend/zend_vm_execute.h @@ -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(); } } diff --git a/ext/pcntl/pcntl.c b/ext/pcntl/pcntl.c index fe4fe104a36..e1aedb101c9 100644 --- a/ext/pcntl/pcntl.c +++ b/ext/pcntl/pcntl.c @@ -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 @@ -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); }