about summary refs log tree commit diff
diff options
context:
space:
mode:
authorMatthias Krüger <matthias.krueger@famsik.de>2021-10-14 16:06:44 +0200
committerGitHub <noreply@github.com>2021-10-14 16:06:44 +0200
commitd1777917915f59df0407ddeb16aa9e987481784c (patch)
tree024d7358ba4bd36b0c19c184f3f971d257f7c5f9
parentf9c9774aea914bc2be7ad1bb466a8104592a7933 (diff)
parent273e522af6c7b28704688b2a7b8b423c7472fb3c (diff)
downloadrust-d1777917915f59df0407ddeb16aa9e987481784c.tar.gz
rust-d1777917915f59df0407ddeb16aa9e987481784c.zip
Rollup merge of #89433 - arlosi:stdin-fix, r=joshtriplett
Fix ctrl-c causing reads of stdin to return empty on Windows.

Pressing ctrl+c (or ctrl+break) on Windows caused a blocking read of stdin to unblock and return empty, unlike other platforms which continue to block.

On ctrl-c, `ReadConsoleW` will return success, but also set `LastError` to `ERROR_OPERATION_ABORTED`.

This change detects this case, and re-tries the call to `ReadConsoleW`.

Fixes #89177. See issue for further details.

Tested on Windows 7 and Windows 10 with both MSVC and GNU toolchains
-rw-r--r--library/std/src/sys/windows/stdio.rs28
1 files changed, 19 insertions, 9 deletions
diff --git a/library/std/src/sys/windows/stdio.rs b/library/std/src/sys/windows/stdio.rs
index 2719a530dfd..a4fe5f67f69 100644
--- a/library/std/src/sys/windows/stdio.rs
+++ b/library/std/src/sys/windows/stdio.rs
@@ -291,15 +291,25 @@ fn read_u16s(handle: c::HANDLE, buf: &mut [u16]) -> io::Result<usize> {
     };
 
     let mut amount = 0;
-    cvt(unsafe {
-        c::ReadConsoleW(
-            handle,
-            buf.as_mut_ptr() as c::LPVOID,
-            buf.len() as u32,
-            &mut amount,
-            &mut input_control as c::PCONSOLE_READCONSOLE_CONTROL,
-        )
-    })?;
+    loop {
+        cvt(unsafe {
+            c::SetLastError(0);
+            c::ReadConsoleW(
+                handle,
+                buf.as_mut_ptr() as c::LPVOID,
+                buf.len() as u32,
+                &mut amount,
+                &mut input_control as c::PCONSOLE_READCONSOLE_CONTROL,
+            )
+        })?;
+
+        // ReadConsoleW returns success with ERROR_OPERATION_ABORTED for Ctrl-C or Ctrl-Break.
+        // Explicitly check for that case here and try again.
+        if amount == 0 && unsafe { c::GetLastError() } == c::ERROR_OPERATION_ABORTED {
+            continue;
+        }
+        break;
+    }
 
     if amount > 0 && buf[amount as usize - 1] == CTRL_Z {
         amount -= 1;