From a8ffc7fd45592fd423d44852383efb3c6c1a7264 Mon Sep 17 00:00:00 2001 From: Chris Denton Date: Wed, 6 Jul 2022 16:39:06 +0100 Subject: [PATCH] Tests for unsound Windows file methods --- library/std/src/sys/windows/handle.rs | 3 + library/std/src/sys/windows/handle/tests.rs | 22 ++++++ .../issues-81357-unsound-file-methods.rs | 76 +++++++++++++++++++ 3 files changed, 101 insertions(+) create mode 100644 library/std/src/sys/windows/handle/tests.rs create mode 100644 src/test/ui-fulldeps/issues-81357-unsound-file-methods.rs diff --git a/library/std/src/sys/windows/handle.rs b/library/std/src/sys/windows/handle.rs index 6dd022b0806ba..e24b09cc96ec8 100644 --- a/library/std/src/sys/windows/handle.rs +++ b/library/std/src/sys/windows/handle.rs @@ -1,5 +1,8 @@ #![unstable(issue = "none", feature = "windows_handle")] +#[cfg(test)] +mod tests; + use crate::cmp; use crate::io::{self, ErrorKind, IoSlice, IoSliceMut, Read, ReadBuf}; use crate::mem; diff --git a/library/std/src/sys/windows/handle/tests.rs b/library/std/src/sys/windows/handle/tests.rs new file mode 100644 index 0000000000000..d836dae4c305b --- /dev/null +++ b/library/std/src/sys/windows/handle/tests.rs @@ -0,0 +1,22 @@ +use crate::sys::pipe::{anon_pipe, Pipes}; +use crate::{thread, time}; + +/// Test the synchronous fallback for overlapped I/O. +#[test] +fn overlapped_handle_fallback() { + // Create some pipes. `ours` will be asynchronous. + let Pipes { ours, theirs } = anon_pipe(true, false).unwrap(); + + let async_readable = ours.into_handle(); + let sync_writeable = theirs.into_handle(); + + thread::scope(|_| { + thread::sleep(time::Duration::from_millis(100)); + sync_writeable.write(b"hello world!").unwrap(); + }); + + // The pipe buffer starts empty so reading won't complete synchronously unless + // our fallback path works. + let mut buffer = [0u8; 1024]; + async_readable.read(&mut buffer).unwrap(); +} diff --git a/src/test/ui-fulldeps/issues-81357-unsound-file-methods.rs b/src/test/ui-fulldeps/issues-81357-unsound-file-methods.rs new file mode 100644 index 0000000000000..94b5798a0e7d2 --- /dev/null +++ b/src/test/ui-fulldeps/issues-81357-unsound-file-methods.rs @@ -0,0 +1,76 @@ +// 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 = "\\\\.\\pipe\\repro"; + 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)); + + // In this test, success is indicated by failing. + if buf[0] == b { + panic!("Success!"); + } + } + } + }) + }; + + 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"); + let _ = t1.join(); + let _ = t2.join(); +}