You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Windows: SystemError during os.kill(..., signal.CTRL_C_EVENT) #87128
I don't have an automated test at this time, but here's how to get os.kill to raise SystemError. I did this on Windows 10 version 20H2 (build 19042.746) with Pythons 3.7.7, 3.8.5, and 3.9.1. os_kill_impl at Modules/posixmodule.c:7833 does not appear to have been modified recently (but I haven't checked its transitive callees), so I imagine you can get the same behavior from os.kill on Python 3.10.
Open two consoles, A and B. (I'm using tabs in Windows Terminal, if that matters.)
In console A, type but DO NOT EXECUTE the following command:
Copy or remember the printed PID. Hurry to step 4 before your 60 seconds expires!
In console A, type the PID from console B and execute the command.
In console B, confirm that the Python exited without printing "exiting cleanly". Oddly, echo %errorlevel% will print 0 rather than -1073741510 (which is 2**32 - 0xc000013a, the CTRL_C_EVENT exit code), which is what it prints after python -c"raise KeyboardInturrupt".
In console A, you should see the following traceback.
OSError: [WinError 87] The parameter is incorrect
The above exception was the direct cause of the following exception:
Traceback (most recent call last):
File "<string>", line 1, in <module>SystemError: <built-in function kill> returned a result with an error set
For a new process group, the cancel event is initially ignored, but the break event is always handled. To enable the cancel event, the process must call SetConsoleCtrlHandler(NULL, FALSE), such as via ctypes with kernel32.SetConsoleCtrlHandler(None, False). I think the signal module should provide a function to enable/disable Ctrl+C handling without ctypes, and implicitly enable it when setting a new SIGINT handler.
That's what Lib/test/win_console_handler.py:39 does. What I don't understand is why that's necessary. Isn't that what PyConfig.install_signal_handlers is supposed to do?
Which brings me to how I ended up here in the first place: I wanted to write a test that PyConfig.install_signal_handlers is set in an embedded instance of Python I'm working with. In outline, the following test works on both Windows and macOS *except on Windows running under Tox*.
@unittest.removeHandlerdeftest_signal_handlers_installed(self):
SIG=signal.SIGINTifsys.platform=='win32':
SIG=signal.CTRL_C_EVENTwithself.assertRaises(KeyboardInterrupt):
os.kill(os.getpid(), SIG)
ifsys.platform=='win32':
time.sleep(.1) # Give handler's thread time to join
Using SetConsoleCtrlHandler if I detect that I'm running on Windows under Tox would, if I understand correctly, hide whether PyConfig.install_signal_handlers was set before the Python I'm running in started, right? (I know this isn't the right venue for discussing my embedding/testing problem. But maybe the use case informs the pending discussion of what to do about os.kill's semantics.)
SetConsoleCtrlHandler(None, False) clears the Ctrl+C ignore flag in the PEB ProcessParameters, which is normally inherited by child processes. But using the CREATE_NEW_PROCESS_GROUP creation flag always causes Ctrl+C to be initially ignored in the process. The intent is to make it a 'background' process by default, to support CMD's start /b option.
Win32KillTests in Lib/test/test_os.py incorrectly assumes it only has to enable Ctrl+C in the parent process. win_console_handler.py incorrectly assumes it does not have to call SetConsoleCtrlHandler(None, False). This is why test_CTRL_C_EVENT() is currently being skipped. To fix it, win_console_handler.py needs to call SetConsoleCtrlHandler(None, False).
Isn't that what PyConfig.install_signal_handlers is supposed to do?
The C runtime's signal() function does not clear the Ctrl+C ignore flag when a SIGINT handler is set. I think Python should. It's expected behavior for POSIX compatibility.
with self.assertRaises(KeyboardInterrupt):
os.kill(os.getpid(), SIG)
Unless you know the current process was created in a new process group, it is not correct to call os.kill(os.getpid(), signal.CTRL_C_EVENT). You'd be better off using os.kill(0, signal.CTRL_C_EVENT) and ensuring that Ctrl+C is temporarily ignored in the parent process, if that's in your control. Also, Python 3.8 added raise_signal(), which calls C raise(), so a more reliable way to test just the signal handler is to call signal.raise_signal(signal.SIGINT). This also eliminates needing to synchronize with the console control thread.
Thanks, Terry. I should have followed up with a short message asking for a core developer to sign off on that suggestion, in which case this is an "easy (C)" issue.
elsamuko commented on Feb 26, 2021
elsamukomannequin
Mannequin
More actions
FWIW, I could send CTRL-C to ffmpeg (else it won't write a valid mp4 header) under Windows by using the WINPID and not the PID returned from ps .
El Samuko, is that a Windows (Win32), Cygwin, MSYS2, WSL, or some other version of bash? The same for Python, and which version of Python is it. With these details, I can tell you what os.kill($WINPID, signal.CTRL_C_EVENT)" is probably doing.
Activity
wkschwartz commentedon Jan 18, 2021
I don't have an automated test at this time, but here's how to get os.kill to raise SystemError. I did this on Windows 10 version 20H2 (build 19042.746) with Pythons 3.7.7, 3.8.5, and 3.9.1. os_kill_impl at Modules/posixmodule.c:7833 does not appear to have been modified recently (but I haven't checked its transitive callees), so I imagine you can get the same behavior from os.kill on Python 3.10.
python -c"import os, signal; os.kill(, signal.CTRL_C_EVENT)"
Move your cursor back before the comma.
python -c"import os, time; print(os.getpid()); time.sleep(60); print('exiting cleanly')"
Copy or remember the printed PID. Hurry to step 4 before your 60 seconds expires!
echo %errorlevel%will print0rather than-1073741510(which is2**32 - 0xc000013a, the CTRL_C_EVENT exit code), which is what it prints afterpython -c"raise KeyboardInturrupt".OSError: [WinError 87] The parameter is incorrect
8 remaining items
wkschwartz commentedon Jan 19, 2021
That's what Lib/test/win_console_handler.py:39 does. What I don't understand is why that's necessary. Isn't that what PyConfig.install_signal_handlers is supposed to do?
Which brings me to how I ended up here in the first place: I wanted to write a test that PyConfig.install_signal_handlers is set in an embedded instance of Python I'm working with. In outline, the following test works on both Windows and macOS *except on Windows running under Tox*.
Using SetConsoleCtrlHandler if I detect that I'm running on Windows under Tox would, if I understand correctly, hide whether PyConfig.install_signal_handlers was set before the Python I'm running in started, right? (I know this isn't the right venue for discussing my embedding/testing problem. But maybe the use case informs the pending discussion of what to do about os.kill's semantics.)
eryksun commentedon Jan 19, 2021
No, that script is currently broken.
SetConsoleCtrlHandler(None, False) clears the Ctrl+C ignore flag in the PEB ProcessParameters, which is normally inherited by child processes. But using the CREATE_NEW_PROCESS_GROUP creation flag always causes Ctrl+C to be initially ignored in the process. The intent is to make it a 'background' process by default, to support CMD's
start /boption.Win32KillTests in Lib/test/test_os.py incorrectly assumes it only has to enable Ctrl+C in the parent process. win_console_handler.py incorrectly assumes it does not have to call SetConsoleCtrlHandler(None, False). This is why test_CTRL_C_EVENT() is currently being skipped. To fix it, win_console_handler.py needs to call SetConsoleCtrlHandler(None, False).
The C runtime's signal() function does not clear the Ctrl+C ignore flag when a SIGINT handler is set. I think Python should. It's expected behavior for POSIX compatibility.
Unless you know the current process was created in a new process group, it is not correct to call os.kill(os.getpid(), signal.CTRL_C_EVENT). You'd be better off using os.kill(0, signal.CTRL_C_EVENT) and ensuring that Ctrl+C is temporarily ignored in the parent process, if that's in your control. Also, Python 3.8 added raise_signal(), which calls C raise(), so a more reliable way to test just the signal handler is to call signal.raise_signal(signal.SIGINT). This also eliminates needing to synchronize with the console control thread.
terryjreedy commentedon Jan 23, 2021
If I understand correctly, this is open for someone to evaluate Eryk's suggestion in msg385291 that a 'missing' return be added to win32_kill.
eryksun commentedon Jan 23, 2021
Thanks, Terry. I should have followed up with a short message asking for a core developer to sign off on that suggestion, in which case this is an "easy (C)" issue.
elsamuko commentedon Feb 26, 2021
FWIW, I could send CTRL-C to ffmpeg (else it won't write a valid mp4 header) under Windows by using the WINPID and not the PID returned from ps .
I put an example here:
https://gist.github.com/elsamuko/9c3fe69f00a0f847251ffa3ef1d080a2
eryksun commentedon Feb 26, 2021
El Samuko, is that a Windows (Win32), Cygwin, MSYS2, WSL, or some other version of bash? The same for Python, and which version of Python is it. With these details, I can tell you what
os.kill($WINPID, signal.CTRL_C_EVENT)"is probably doing.elsamuko commentedon Feb 26, 2021
@eryksun
I can run the script successfully under cygwin and mingw(git bash).
The python version is 3.9.2
elsamuko commentedon Feb 26, 2021
I'm getting [WinError 87], too, when using the PID.
davetapley commentedon Jan 20, 2023
@eryksun do you remember how/why this was closed?
I just ran in to it on 3.10.9.