Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 31 additions & 0 deletions sapi/cli/tests/sapi_windows_set_ctrl_trampoline.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
--TEST--
sapi_windows_set_ctrl_handler() trampoline test
--SKIPIF--
<?php
include "skipif.inc";

if (strtoupper(substr(PHP_OS, 0, 3)) !== 'WIN')
die("skip this test is for Windows platforms only");
?>
--FILE--
<?php

class TrampolineTest {
public function __call(string $name, array $arguments) {
echo 'Trampoline for ', $name, PHP_EOL;
}
}
$o = new TrampolineTest();
$callback = [$o, 'trampoline'];

sapi_windows_set_ctrl_handler($callback);

function foo(int $event) { }

sapi_windows_set_ctrl_handler(foo(...));

echo "Done\n";

?>
--EXPECT--
Done
41 changes: 24 additions & 17 deletions win32/signal.c
Original file line number Diff line number Diff line change
Expand Up @@ -18,22 +18,20 @@
#include "win32/console.h"

/* true globals; only used from main thread and from kernel callback */
static zval ctrl_handler;
static zend_fcall_info_cache ctrl_handler;
static DWORD ctrl_evt = (DWORD)-1;
static zend_atomic_bool *vm_interrupt_flag = NULL;

static void (*orig_interrupt_function)(zend_execute_data *execute_data);

static void php_win32_signal_ctrl_interrupt_function(zend_execute_data *execute_data)
{/*{{{*/
if (IS_UNDEF != Z_TYPE(ctrl_handler)) {
zval retval, params[1];
if (ZEND_FCC_INITIALIZED(ctrl_handler)) {
zval params[1];

ZVAL_LONG(&params[0], ctrl_evt);

/* If the function returns, */
call_user_function(NULL, NULL, &ctrl_handler, &retval, 1, params);
zval_ptr_dtor(&retval);
zend_call_known_fcc(&ctrl_handler, NULL, 1, params, NULL);
}

if (orig_interrupt_function) {
Expand All @@ -51,7 +49,7 @@ PHP_WINUTIL_API void php_win32_signal_ctrl_handler_init(void)
orig_interrupt_function = zend_interrupt_function;
zend_interrupt_function = php_win32_signal_ctrl_interrupt_function;
vm_interrupt_flag = &EG(vm_interrupt);
ZVAL_UNDEF(&ctrl_handler);
ctrl_handler = empty_fcall_info_cache;

REGISTER_MAIN_LONG_CONSTANT("PHP_WINDOWS_EVENT_CTRL_C", CTRL_C_EVENT, CONST_PERSISTENT);
REGISTER_MAIN_LONG_CONSTANT("PHP_WINDOWS_EVENT_CTRL_BREAK", CTRL_BREAK_EVENT, CONST_PERSISTENT);
Expand Down Expand Up @@ -82,9 +80,8 @@ PHP_WINUTIL_API void php_win32_signal_ctrl_handler_request_shutdown(void)

/* The ctrl_handler must be cleared between requests, otherwise we can crash
* due to accessing a previous request's memory. */
if (!Z_ISUNDEF(ctrl_handler)) {
zval_ptr_dtor(&ctrl_handler);
ZVAL_UNDEF(&ctrl_handler);
if (ZEND_FCC_INITIALIZED(ctrl_handler)) {
zend_fcc_dtor(&ctrl_handler);
}
}

Expand All @@ -110,37 +107,47 @@ PHP_FUNCTION(sapi_windows_set_ctrl_handler)


/* callable argument corresponds to the CTRL handler */
if (zend_parse_parameters(ZEND_NUM_ARGS(), "f!|b", &fci, &fcc, &add) == FAILURE) {
if (zend_parse_parameters(ZEND_NUM_ARGS(), "F!|b", &fci, &fcc, &add) == FAILURE) {
RETURN_THROWS();
}

#ifdef ZTS
if (!tsrm_is_main_thread()) {
if (ZEND_FCC_INITIALIZED(fcc)) {
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Don't you also need to do this in the !php_win32_console_is_cli_sapi if block?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Indeed.

zend_release_fcall_info_cache(&fcc);
}
zend_throw_error(NULL, "CTRL events can only be received on the main thread");
RETURN_THROWS();
}
#endif

if (!php_win32_console_is_cli_sapi()) {
if (ZEND_FCC_INITIALIZED(fcc)) {
zend_release_fcall_info_cache(&fcc);
}
zend_throw_error(NULL, "CTRL events trapping is only supported on console");
RETURN_THROWS();
}

if (!ZEND_FCI_INITIALIZED(fci)) {
zval_ptr_dtor(&ctrl_handler);
ZVAL_UNDEF(&ctrl_handler);
if (!ZEND_FCC_INITIALIZED(fcc)) {
if (ZEND_FCC_INITIALIZED(ctrl_handler)) {
zend_fcc_dtor(&ctrl_handler);
}
RETURN_BOOL(SetConsoleCtrlHandler(NULL, add));
}

if (!SetConsoleCtrlHandler(NULL, FALSE) || !SetConsoleCtrlHandler(php_win32_signal_system_ctrl_handler, add)) {
zend_string *func_name = zend_get_callable_name(&fci.function_name);
php_error_docref(NULL, E_WARNING, "Unable to attach %s as a CTRL handler", ZSTR_VAL(func_name));
zend_string_release_ex(func_name, 0);
zend_release_fcall_info_cache(&fcc);
RETURN_FALSE;
}

zval_ptr_dtor(&ctrl_handler);
ZVAL_COPY(&ctrl_handler, &fci.function_name);
if (ZEND_FCC_INITIALIZED(ctrl_handler)) {
zend_fcc_dtor(&ctrl_handler);
}
zend_fcc_dup(&ctrl_handler, &fcc);

RETURN_TRUE;
}/*}}}*/
Expand All @@ -163,7 +170,7 @@ PHP_FUNCTION(sapi_windows_generate_ctrl_event)

ret = (GenerateConsoleCtrlEvent(evt, pid) != 0);

if (IS_UNDEF != Z_TYPE(ctrl_handler)) {
if (ZEND_FCC_INITIALIZED(ctrl_handler)) {
ret = ret && SetConsoleCtrlHandler(php_win32_signal_system_ctrl_handler, TRUE);
}

Expand Down