Change:
<ins> // run-fail // only-windows fn main() { use std::fs; use std::io::prelude::*; use std::os::windows::prelude::*; use std::ptr; use std::sync::Arc; use std::thread; use std::time::Duration; const FILE_FLAG_OVERLAPPED: u32 = 0x40000000; fn create_pipe_server(path: &str) -> fs::File { let mut path0 = path.as_bytes().to_owned(); path0.push(0); extern "system" { fn CreateNamedPipeA( lpName: *const u8, dwOpenMode: u32, dwPipeMode: u32, nMaxInstances: u32, nOutBufferSize: u32, nInBufferSize: u32, nDefaultTimeOut: u32, lpSecurityAttributes: *mut u8, ) -> RawHandle; } unsafe { let h = CreateNamedPipeA(path0.as_ptr(), 3, 0, 1, 0, 0, 0, ptr::null_mut()); assert_ne!(h as isize, -1); fs::File::from_raw_handle(h) } } let path = ".piperepro"; let mut server = create_pipe_server(path); let client = Arc::new( fs::OpenOptions::new().custom_flags(FILE_FLAG_OVERLAPPED).read(true).open(path).unwrap(), ); let spawn_read = |is_first: bool| { thread::spawn({ let f = client.clone(); move || { let mut buf = [0xcc; 1]; let mut f = f.as_ref(); f.read(&mut buf).unwrap(); if is_first { assert_ne!(buf[0], 0xcc); } else { let b = buf[0]; // capture buf[0] thread::sleep(Duration::from_millis(200)); // Check the buffer hasn't been written to after read. dbg!(buf[0], b); assert_eq!(buf[0], b); } } }) }; let t1 = spawn_read(true); thread::sleep(Duration::from_millis(20)); let t2 = spawn_read(false); thread::sleep(Duration::from_millis(100)); let _ = server.write(b"x"); thread::sleep(Duration::from_millis(100)); let _ = server.write(b"y"); // This is run fail because we need to test for the `abort`. // That failing to run is the success case. if t1.join().is_err() || t2.join().is_err() { return; } else { panic!("success"); } } </ins>

Discussion:
on windows. with and rename it back to git bash I expected to see this happen: my really long string gets printed twice, followed by a clean exit Instead, this happened: some amount of my really long string gets printed, followed by: The test case, while simple, does appear to have a minimum size requirement to trigger this crash. Shrinking the string will cause it to stop crashing. I'm using in the steps for simplicity, but we've observed this happening with other programs at the end of the pipe too. Redirecting to a file instead of a pipe seems to not trigger this crash. Using is not necessary to trigger the crash, running the built executable directly also crashes. This PR this new error condition: I am not the only one seeing this new error message: modify labels: +regression-from-stable-to-stable +O-windows
I believe this must be because git bash (cygwin? msys?) is opening pipes between processes with . In my original bug report, I suggested calling once if returned , since that will at least resolve the pending IO correctly in the case where the file is not being used for other IOs concurrently. This would cover this and other cases at least as well as the original code calling . This isn't perfect, since of course takes , so you can probably deadlock in a multi-threaded process in this async pipe configuration. But it would at least avoid the common case. However, it seems that this got missed from the actual change (sorry, I should have caught that). Is there a reason this was skipped?
Oh, hrm. That looks like an oversight on my part. I'll PR a fix asap.
Thanks for fixing the issue quickly. When the PR that fixes this issue is merged, will a patch release 1.62.1 be published? Or will we have to wait for a fix in 1.63?
PR was nominated and accepted for both beta and stable backport by T-libs. Leaving this open until those play out. Assigning P-high for the same reasons it was accepted for backports.