Skip to content

Commit 27ae51d

Browse files
committed
win32/signal.c: convert ctrl_handler to FCC
1 parent a22c56c commit 27ae51d

3 files changed

Lines changed: 53 additions & 18 deletions

File tree

sapi/cli/tests/sapi_windows_set_ctrl_handler_leak.phpt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
--TEST--
2-
sapi_windows_set_ctrl_handler() leak bug
2+
sapi_windows_set_ctrl_handler() trampoline test
33
--SKIPIF--
44
<?php
55
include "skipif.inc";
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
--TEST--
2+
sapi_windows_set_ctrl_handler() leak bug
3+
--SKIPIF--
4+
<?php
5+
include "skipif.inc";
6+
7+
if (strtoupper(substr(PHP_OS, 0, 3)) !== 'WIN')
8+
die("skip this test is for Windows platforms only");
9+
?>
10+
--FILE--
11+
<?php
12+
13+
class TrampolineTest {
14+
public function __call(string $name, array $arguments) {
15+
echo 'Trampoline for ', $name, PHP_EOL;
16+
}
17+
}
18+
$o = new TrampolineTest();
19+
$callback = [$o, 'trampoline'];
20+
21+
sapi_windows_set_ctrl_handler($callback);
22+
23+
function foo(int $event) { }
24+
25+
sapi_windows_set_ctrl_handler(foo(...));
26+
27+
echo "Done\n";
28+
29+
?>
30+
--EXPECT--
31+
Done

win32/signal.c

Lines changed: 21 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -18,22 +18,20 @@
1818
#include "win32/console.h"
1919

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

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

2727
static void php_win32_signal_ctrl_interrupt_function(zend_execute_data *execute_data)
2828
{/*{{{*/
29-
if (IS_UNDEF != Z_TYPE(ctrl_handler)) {
30-
zval retval, params[1];
29+
if (ZEND_FCC_INITIALIZED(ctrl_handler)) {
30+
zval params[1];
3131

3232
ZVAL_LONG(&params[0], ctrl_evt);
3333

34-
/* If the function returns, */
35-
call_user_function(NULL, NULL, &ctrl_handler, &retval, 1, params);
36-
zval_ptr_dtor(&retval);
34+
zend_call_known_fcc(&ctrl_handler, NULL, 1, params, NULL);
3735
}
3836

3937
if (orig_interrupt_function) {
@@ -51,7 +49,7 @@ PHP_WINUTIL_API void php_win32_signal_ctrl_handler_init(void)
5149
orig_interrupt_function = zend_interrupt_function;
5250
zend_interrupt_function = php_win32_signal_ctrl_interrupt_function;
5351
vm_interrupt_flag = &EG(vm_interrupt);
54-
ZVAL_UNDEF(&ctrl_handler);
52+
ctrl_handler = empty_fcall_info_cache;
5553

5654
REGISTER_MAIN_LONG_CONSTANT("PHP_WINDOWS_EVENT_CTRL_C", CTRL_C_EVENT, CONST_PERSISTENT);
5755
REGISTER_MAIN_LONG_CONSTANT("PHP_WINDOWS_EVENT_CTRL_BREAK", CTRL_BREAK_EVENT, CONST_PERSISTENT);
@@ -82,9 +80,8 @@ PHP_WINUTIL_API void php_win32_signal_ctrl_handler_request_shutdown(void)
8280

8381
/* The ctrl_handler must be cleared between requests, otherwise we can crash
8482
* due to accessing a previous request's memory. */
85-
if (!Z_ISUNDEF(ctrl_handler)) {
86-
zval_ptr_dtor(&ctrl_handler);
87-
ZVAL_UNDEF(&ctrl_handler);
83+
if (ZEND_FCC_INITIALIZED(ctrl_handler)) {
84+
zend_fcc_dtor(&ctrl_handler);
8885
}
8986
}
9087

@@ -110,12 +107,15 @@ PHP_FUNCTION(sapi_windows_set_ctrl_handler)
110107

111108

112109
/* callable argument corresponds to the CTRL handler */
113-
if (zend_parse_parameters(ZEND_NUM_ARGS(), "f!|b", &fci, &fcc, &add) == FAILURE) {
110+
if (zend_parse_parameters(ZEND_NUM_ARGS(), "F!|b", &fci, &fcc, &add) == FAILURE) {
114111
RETURN_THROWS();
115112
}
116113

117114
#ifdef ZTS
118115
if (!tsrm_is_main_thread()) {
116+
if (ZEND_FCC_INITIALIZED(fcc)) {
117+
zend_release_fcall_info_cache(&fcc);
118+
}
119119
zend_throw_error(NULL, "CTRL events can only be received on the main thread");
120120
RETURN_THROWS();
121121
}
@@ -126,21 +126,25 @@ PHP_FUNCTION(sapi_windows_set_ctrl_handler)
126126
RETURN_THROWS();
127127
}
128128

129-
if (!ZEND_FCI_INITIALIZED(fci)) {
130-
zval_ptr_dtor(&ctrl_handler);
131-
ZVAL_UNDEF(&ctrl_handler);
129+
if (!ZEND_FCC_INITIALIZED(fcc)) {
130+
if (ZEND_FCC_INITIALIZED(ctrl_handler)) {
131+
zend_fcc_dtor(&ctrl_handler);
132+
}
132133
RETURN_BOOL(SetConsoleCtrlHandler(NULL, add));
133134
}
134135

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

142-
zval_ptr_dtor(&ctrl_handler);
143-
ZVAL_COPY(&ctrl_handler, &fci.function_name);
144+
if (ZEND_FCC_INITIALIZED(ctrl_handler)) {
145+
zend_fcc_dtor(&ctrl_handler);
146+
}
147+
zend_fcc_dup(&ctrl_handler, &fcc);
144148

145149
RETURN_TRUE;
146150
}/*}}}*/
@@ -163,7 +167,7 @@ PHP_FUNCTION(sapi_windows_generate_ctrl_event)
163167

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

166-
if (IS_UNDEF != Z_TYPE(ctrl_handler)) {
170+
if (ZEND_FCC_INITIALIZED(ctrl_handler)) {
167171
ret = ret && SetConsoleCtrlHandler(php_win32_signal_system_ctrl_handler, TRUE);
168172
}
169173

0 commit comments

Comments
 (0)