std: win: Don't use SetHandleInformation on UWP

Attempt to create sockets with the WSA_FLAG_NO_HANDLE_INHERIT flag, and
handle the potential error gracefully (as the flag isn't support on
Windows 7 before SP1)
This commit is contained in:
Hugo Beauzée-Luyssen 2019-05-27 16:51:29 +02:00
parent 9407ed759f
commit a713a0399a
4 changed files with 61 additions and 19 deletions

View file

@ -121,6 +121,7 @@ impl Clone for WIN32_FIND_DATAW {
}
pub const WSA_FLAG_OVERLAPPED: DWORD = 0x01;
pub const WSA_FLAG_NO_HANDLE_INHERIT: DWORD = 0x80;
pub const WSADESCRIPTION_LEN: usize = 256;
pub const WSASYS_STATUS_LEN: usize = 128;
@ -130,6 +131,7 @@ pub const INVALID_SOCKET: SOCKET = !0;
pub const WSAEACCES: c_int = 10013;
pub const WSAEINVAL: c_int = 10022;
pub const WSAEWOULDBLOCK: c_int = 10035;
pub const WSAEPROTOTYPE: c_int = 10041;
pub const WSAEADDRINUSE: c_int = 10048;
pub const WSAEADDRNOTAVAIL: c_int = 10049;
pub const WSAECONNABORTED: c_int = 10053;
@ -157,8 +159,6 @@ pub const STD_INPUT_HANDLE: DWORD = -10i32 as DWORD;
pub const STD_OUTPUT_HANDLE: DWORD = -11i32 as DWORD;
pub const STD_ERROR_HANDLE: DWORD = -12i32 as DWORD;
pub const HANDLE_FLAG_INHERIT: DWORD = 0x00000001;
pub const PROGRESS_CONTINUE: DWORD = 0;
pub const ERROR_FILE_NOT_FOUND: DWORD = 2;
@ -658,9 +658,15 @@ pub struct timeval {
// Functions forbidden when targeting UWP
cfg_if::cfg_if! {
if #[cfg(not(target_vendor = "uwp"))] {
pub const HANDLE_FLAG_INHERIT: DWORD = 0x00000001;
extern "system" {
#[link_name = "SystemFunction036"]
pub fn RtlGenRandom(RandomBuffer: *mut u8, RandomBufferLength: ULONG) -> BOOLEAN;
pub fn SetHandleInformation(hObject: HANDLE,
dwMask: DWORD,
dwFlags: DWORD) -> BOOL;
}
}
}
@ -772,9 +778,6 @@ extern "system" {
pub fn GetUserProfileDirectoryW(hToken: HANDLE,
lpProfileDir: LPWSTR,
lpcchSize: *mut DWORD) -> BOOL;
pub fn SetHandleInformation(hObject: HANDLE,
dwMask: DWORD,
dwFlags: DWORD) -> BOOL;
pub fn CopyFileExW(lpExistingFileName: LPCWSTR,
lpNewFileName: LPCWSTR,
lpProgressRoutine: LPPROGRESS_ROUTINE,

View file

@ -97,12 +97,26 @@ impl Socket {
};
let socket = unsafe {
match c::WSASocketW(fam, ty, 0, ptr::null_mut(), 0,
c::WSA_FLAG_OVERLAPPED) {
c::INVALID_SOCKET => Err(last_error()),
c::WSA_FLAG_OVERLAPPED | c::WSA_FLAG_NO_HANDLE_INHERIT) {
c::INVALID_SOCKET => {
match c::WSAGetLastError() {
c::WSAEPROTOTYPE => {
match c::WSASocketW(fam, ty, 0, ptr::null_mut(), 0,
c::WSA_FLAG_OVERLAPPED) {
c::INVALID_SOCKET => Err(last_error()),
n => {
let s = Socket(n);
s.set_no_inherit()?;
Ok(s)
},
}
},
n => Err(io::Error::from_raw_os_error(n)),
}
},
n => Ok(Socket(n)),
}
}?;
socket.set_no_inherit()?;
Ok(socket)
}
@ -168,7 +182,6 @@ impl Socket {
n => Ok(Socket(n)),
}
}?;
socket.set_no_inherit()?;
Ok(socket)
}
@ -178,16 +191,34 @@ impl Socket {
cvt(c::WSADuplicateSocketW(self.0,
c::GetCurrentProcessId(),
&mut info))?;
match c::WSASocketW(info.iAddressFamily,
info.iSocketType,
info.iProtocol,
&mut info, 0,
c::WSA_FLAG_OVERLAPPED) {
c::INVALID_SOCKET => Err(last_error()),
c::WSA_FLAG_OVERLAPPED | c::WSA_FLAG_NO_HANDLE_INHERIT) {
c::INVALID_SOCKET => {
match c::WSAGetLastError() {
c::WSAEPROTOTYPE => {
match c::WSASocketW(info.iAddressFamily,
info.iSocketType,
info.iProtocol,
&mut info, 0,
c::WSA_FLAG_OVERLAPPED) {
c::INVALID_SOCKET => Err(last_error()),
n => {
let s = Socket(n);
s.set_no_inherit()?;
Ok(s)
},
}
},
n => Err(io::Error::from_raw_os_error(n)),
}
},
n => Ok(Socket(n)),
}
}?;
socket.set_no_inherit()?;
Ok(socket)
}
@ -312,6 +343,7 @@ impl Socket {
}
}
#[cfg(not(target_vendor = "uwp"))]
fn set_no_inherit(&self) -> io::Result<()> {
sys::cvt(unsafe {
c::SetHandleInformation(self.0 as c::HANDLE,
@ -319,6 +351,11 @@ impl Socket {
}).map(|_| ())
}
#[cfg(target_vendor = "uwp")]
fn set_no_inherit(&self) -> io::Result<()> {
Err(io::Error::new(io::ErrorKind::Other, "Unavailable on UWP"))
}
pub fn shutdown(&self, how: Shutdown) -> io::Result<()> {
let how = match how {
Shutdown::Write => c::SD_SEND,

View file

@ -45,7 +45,7 @@ pub struct Pipes {
/// mode. This means that technically speaking it should only ever be used
/// with `OVERLAPPED` instances, but also works out ok if it's only ever used
/// once at a time (which we do indeed guarantee).
pub fn anon_pipe(ours_readable: bool) -> io::Result<Pipes> {
pub fn anon_pipe(ours_readable: bool, their_handle_inheritable: bool) -> io::Result<Pipes> {
// Note that we specifically do *not* use `CreatePipe` here because
// unfortunately the anonymous pipes returned do not support overlapped
// operations. Instead, we create a "hopefully unique" name and create a
@ -137,6 +137,13 @@ pub fn anon_pipe(ours_readable: bool) -> io::Result<Pipes> {
opts.write(ours_readable);
opts.read(!ours_readable);
opts.share_mode(0);
let size = mem::size_of::<c::SECURITY_ATTRIBUTES>();
let mut sa = c::SECURITY_ATTRIBUTES {
nLength: size as c::DWORD,
lpSecurityDescriptor: ptr::null_mut(),
bInheritHandle: their_handle_inheritable as i32,
};
opts.security_attributes(&mut sa);
let theirs = File::open(Path::new(&name), &opts)?;
let theirs = AnonPipe { inner: theirs.into_handle() };

View file

@ -267,13 +267,8 @@ impl Stdio {
Stdio::MakePipe => {
let ours_readable = stdio_id != c::STD_INPUT_HANDLE;
let pipes = pipe::anon_pipe(ours_readable)?;
let pipes = pipe::anon_pipe(ours_readable, true)?;
*pipe = Some(pipes.ours);
cvt(unsafe {
c::SetHandleInformation(pipes.theirs.handle().raw(),
c::HANDLE_FLAG_INHERIT,
c::HANDLE_FLAG_INHERIT)
})?;
Ok(pipes.theirs.into_handle())
}