Skip to content
Open
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
2 changes: 1 addition & 1 deletion sapi/cli/tests/sapi_windows_set_ctrl_handler_leak.phpt
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
--TEST--
sapi_windows_set_ctrl_handler() leak bug
sapi_windows_set_ctrl_handler() trampoline test
--SKIPIF--
<?php
include "skipif.inc";
Expand Down
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() leak bug
--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
38 changes: 21 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,12 +107,15 @@ 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)) {
zend_release_fcall_info_cache(&fcc);
}
zend_throw_error(NULL, "CTRL events can only be received on the main thread");
RETURN_THROWS();
}
Expand All @@ -126,21 +126,25 @@ PHP_FUNCTION(sapi_windows_set_ctrl_handler)
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 +167,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