https://github.com/python/cpython/commit/c922aa0ddd264395cd606fdfd20512fa54108cfb
commit: c922aa0ddd264395cd606fdfd20512fa54108cfb
branch: main
author: Serhiy Storchaka <[email protected]>
committer: serhiy-storchaka <[email protected]>
date: 2026-08-29T21:05:33+03:00
summary:

gh-72353: Continue reading from the console after ignored Ctrl+C (GH-155434)

If the console cancels a read because of Ctrl+C, but the SIGINT handler
does not raise an exception, restart the read instead of ending it as if
at end of file.

Co-authored-by: Valeriya Sinevich <[email protected]>
Co-authored-by: Zackery Spytz <[email protected]>

files:
A Misc/NEWS.d/next/Windows/2026-08-09-14-20-00.gh-issue-72353.Vw7Kq2.rst
M Modules/_io/winconsoleio.c
M Parser/myreadline.c

diff --git 
a/Misc/NEWS.d/next/Windows/2026-08-09-14-20-00.gh-issue-72353.Vw7Kq2.rst 
b/Misc/NEWS.d/next/Windows/2026-08-09-14-20-00.gh-issue-72353.Vw7Kq2.rst
new file mode 100644
index 000000000000000..95c771823ab77f5
--- /dev/null
+++ b/Misc/NEWS.d/next/Windows/2026-08-09-14-20-00.gh-issue-72353.Vw7Kq2.rst
@@ -0,0 +1,3 @@
+Reading from the console on Windows now continues if the read was cancelled
+by Ctrl+C, but the :const:`~signal.SIGINT` handler did not raise an
+exception.  Previously the read ended as if at end of file.
diff --git a/Modules/_io/winconsoleio.c b/Modules/_io/winconsoleio.c
index 4cd71094e8f459e..e96c5bd738fe0ad 100644
--- a/Modules/_io/winconsoleio.c
+++ b/Modules/_io/winconsoleio.c
@@ -644,8 +644,8 @@ read_console_w(HANDLE handle, DWORD maxlen, DWORD *readlen) 
{
                 break;
             err = 0;
             HANDLE hInterruptEvent = _PyOS_SigintEvent();
-            if (WaitForSingleObjectEx(hInterruptEvent, 100, FALSE)
-                    == WAIT_OBJECT_0) {
+            DWORD state = WaitForSingleObjectEx(hInterruptEvent, 100, FALSE);
+            if (state == WAIT_OBJECT_0) {
                 ResetEvent(hInterruptEvent);
                 Py_BLOCK_THREADS
                 sig = PyErr_CheckSignals();
@@ -653,6 +653,13 @@ read_console_w(HANDLE handle, DWORD maxlen, DWORD 
*readlen) {
                 if (sig < 0)
                     break;
             }
+            else if (state != WAIT_TIMEOUT) {
+                err = GetLastError();
+                break;
+            }
+            /* The console cancelled the read and flushed its input buffer,
+               but no exception was raised.  Start the read over. */
+            continue;
         }
         *readlen += n;
 
diff --git a/Parser/myreadline.c b/Parser/myreadline.c
index 457b9598a0e61a5..339f55afa0dcfaa 100644
--- a/Parser/myreadline.c
+++ b/Parser/myreadline.c
@@ -162,8 +162,8 @@ _PyOS_WindowsConsoleReadline(PyThreadState *tstate, HANDLE 
hStdIn)
                 goto exit;
             err = 0;
             HANDLE hInterruptEvent = _PyOS_SigintEvent();
-            if (WaitForSingleObjectEx(hInterruptEvent, 100, FALSE)
-                    == WAIT_OBJECT_0) {
+            DWORD state = WaitForSingleObjectEx(hInterruptEvent, 100, FALSE);
+            if (state == WAIT_OBJECT_0) {
                 ResetEvent(hInterruptEvent);
                 PyEval_RestoreThread(tstate);
                 s = PyErr_CheckSignals();
@@ -172,7 +172,13 @@ _PyOS_WindowsConsoleReadline(PyThreadState *tstate, HANDLE 
hStdIn)
                     goto exit;
                 }
             }
-            break;
+            else if (state != WAIT_TIMEOUT) {
+                err = GetLastError();
+                goto exit;
+            }
+            /* The console cancelled the read and flushed its input buffer,
+               but no exception was raised.  Start the read over. */
+            continue;
         }
 
         total_read += n_read;

_______________________________________________
Python-checkins mailing list -- [email protected]
To unsubscribe send an email to [email protected]
https://mail.python.org/mailman3//lists/python-checkins.python.org
Member address: [email protected]

Reply via email to