diff --git a/Cargo.toml b/Cargo.toml index bf9f3e147..cd1ccaf5c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -65,7 +65,7 @@ targets = [ "aarch64-linux-android", "x86_64-apple-darwin", "x86_64-pc-windows-msvc", - "x86_64-sun-solaris", + "x86_64-pc-solaris", "x86_64-unknown-dragonfly", "x86_64-unknown-freebsd", "x86_64-unknown-linux-gnu", diff --git a/Makefile b/Makefile index fb4453826..8f797612c 100644 --- a/Makefile +++ b/Makefile @@ -1,5 +1,5 @@ # Targets available via Rustup that are supported. -TARGETS ?= "aarch64-apple-ios" "aarch64-linux-android" "x86_64-apple-darwin" "x86_64-pc-windows-msvc" "x86_64-sun-solaris" "x86_64-unknown-freebsd" "x86_64-unknown-linux-gnu" "x86_64-unknown-netbsd" +TARGETS ?= "aarch64-apple-ios" "aarch64-linux-android" "x86_64-apple-darwin" "x86_64-pc-windows-msvc" "x86_64-pc-solaris" "x86_64-unknown-freebsd" "x86_64-unknown-linux-gnu" "x86_64-unknown-netbsd" test: cargo test --all-features diff --git a/ci/azure-cross-compile.yml b/ci/azure-cross-compile.yml index 763828a43..73225df37 100644 --- a/ci/azure-cross-compile.yml +++ b/ci/azure-cross-compile.yml @@ -32,7 +32,7 @@ jobs: Solaris: vmImage: ubuntu-16.04 - target: x86_64-sun-solaris + target: x86_64-pc-solaris pool: vmImage: $(vmImage) diff --git a/src/sys/windows/named_pipe.rs b/src/sys/windows/named_pipe.rs index 5f643596b..c51df3907 100644 --- a/src/sys/windows/named_pipe.rs +++ b/src/sys/windows/named_pipe.rs @@ -1,41 +1,21 @@ -use crate::event::Source; -use crate::sys::windows::{Event, Overlapped}; -use crate::{poll, Registry}; -use winapi::um::minwinbase::OVERLAPPED_ENTRY; - use std::ffi::OsStr; -use std::fmt; use std::io::{self, Read, Write}; -use std::mem; use std::os::windows::io::{AsRawHandle, FromRawHandle, IntoRawHandle, RawHandle}; -use std::slice; use std::sync::atomic::Ordering::{Relaxed, SeqCst}; use std::sync::atomic::{AtomicBool, AtomicUsize}; use std::sync::{Arc, Mutex}; +use std::{fmt, mem, slice}; -use crate::{Interest, Token}; use miow::iocp::{CompletionPort, CompletionStatus}; use miow::pipe; use winapi::shared::winerror::{ERROR_BROKEN_PIPE, ERROR_PIPE_LISTENING}; use winapi::um::ioapiset::CancelIoEx; +use winapi::um::minwinbase::{OVERLAPPED, OVERLAPPED_ENTRY}; -/// # Safety -/// -/// Only valid if the strict is annotated with `#[repr(C)]`. This is only used -/// with `Overlapped` and `Inner`, which are correctly annotated. -macro_rules! offset_of { - ($t:ty, $($field:ident).+) => ( - &(*(0 as *const $t)).$($field).+ as *const _ as usize - ) -} - -macro_rules! overlapped2arc { - ($e:expr, $t:ty, $($field:ident).+) => ({ - let offset = offset_of!($t, $($field).+); - debug_assert!(offset < mem::size_of::<$t>()); - Arc::from_raw(($e as usize - offset) as *mut $t) - }) -} +use crate::event::Source; +use crate::sys::windows::{Event, Overlapped}; +use crate::{poll, Registry}; +use crate::{Interest, Token}; /// Non-blocking windows named pipe. /// @@ -83,21 +63,72 @@ pub struct NamedPipe { inner: Arc, } +/// # Notes +/// +/// The memory layout of this structure must be fixed as the +/// `ptr_from_*_overlapped` methods depend on it, see the `ptr_from` test. #[repr(C)] struct Inner { - handle: pipe::NamedPipe, - + // NOTE: careful modifying the order of these three fields, the `ptr_from_*` + // methods depend on the layout! connect: Overlapped, - connecting: AtomicBool, - read: Overlapped, write: Overlapped, - + // END NOTE. + handle: pipe::NamedPipe, + connecting: AtomicBool, io: Mutex, - pool: Mutex, } +impl Inner { + /// Converts a pointer to `Inner.connect` to a pointer to `Inner`. + /// + /// # Unsafety + /// + /// Caller must ensure `ptr` is pointing to `Inner.connect`. + unsafe fn ptr_from_conn_overlapped(ptr: *mut OVERLAPPED) -> *const Inner { + // `connect` is the first field, so the pointer are the same. + ptr.cast() + } + + /// Same as [`ptr_from_conn_overlapped`] but for `Inner.read`. + unsafe fn ptr_from_read_overlapped(ptr: *mut OVERLAPPED) -> *const Inner { + // `read` is after `connect: Overlapped`. + (ptr as *mut Overlapped).wrapping_sub(1) as *const Inner + } + + /// Same as [`ptr_from_conn_overlapped`] but for `Inner.write`. + unsafe fn ptr_from_write_overlapped(ptr: *mut OVERLAPPED) -> *const Inner { + // `read` is after `connect: Overlapped` and `read: Overlapped`. + (ptr as *mut Overlapped).wrapping_sub(2) as *const Inner + } +} + +#[test] +fn ptr_from() { + use std::mem::ManuallyDrop; + use std::ptr; + + let pipe = unsafe { ManuallyDrop::new(NamedPipe::from_raw_handle(ptr::null_mut())) }; + let inner: &Inner = &pipe.inner; + assert_eq!( + inner as *const Inner, + unsafe { Inner::ptr_from_conn_overlapped(&inner.connect as *const _ as *mut OVERLAPPED) }, + "`ptr_from_conn_overlapped` incorrect" + ); + assert_eq!( + inner as *const Inner, + unsafe { Inner::ptr_from_read_overlapped(&inner.read as *const _ as *mut OVERLAPPED) }, + "`ptr_from_read_overlapped` incorrect" + ); + assert_eq!( + inner as *const Inner, + unsafe { Inner::ptr_from_write_overlapped(&inner.write as *const _ as *mut OVERLAPPED) }, + "`ptr_from_write_overlapped` incorrect" + ); +} + struct Io { // Uniquely identifies the selector associated with this named pipe cp: Option>, @@ -587,7 +618,7 @@ fn connect_done(status: &OVERLAPPED_ENTRY, events: Option<&mut Vec>) { // Acquire the `Arc`. Note that we should be guaranteed that // the refcount is available to us due to the `mem::forget` in // `connect` above. - let me = unsafe { overlapped2arc!(status.overlapped(), Inner, connect) }; + let me = unsafe { Arc::from_raw(Inner::ptr_from_conn_overlapped(status.overlapped())) }; // Flag ourselves as no longer using the `connect` overlapped instances. let prev = me.connecting.swap(false, SeqCst); @@ -613,7 +644,7 @@ fn read_done(status: &OVERLAPPED_ENTRY, events: Option<&mut Vec>) { // Acquire the `FromRawArc`. Note that we should be guaranteed that // the refcount is available to us due to the `mem::forget` in // `schedule_read` above. - let me = unsafe { overlapped2arc!(status.overlapped(), Inner, read) }; + let me = unsafe { Arc::from_raw(Inner::ptr_from_read_overlapped(status.overlapped())) }; // Move from the `Pending` to `Ok` state. let mut io = me.io.lock().unwrap(); @@ -645,7 +676,7 @@ fn write_done(status: &OVERLAPPED_ENTRY, events: Option<&mut Vec>) { // Acquire the `Arc`. Note that we should be guaranteed that // the refcount is available to us due to the `mem::forget` in // `schedule_write` above. - let me = unsafe { overlapped2arc!(status.overlapped(), Inner, write) }; + let me = unsafe { Arc::from_raw(Inner::ptr_from_write_overlapped(status.overlapped())) }; // Make the state change out of `Pending`. If we wrote the entire buffer // then we're writable again and otherwise we schedule another write. diff --git a/tests/regressions.rs b/tests/regressions.rs index 2e2bacd00..f41c6cae5 100644 --- a/tests/regressions.rs +++ b/tests/regressions.rs @@ -9,7 +9,7 @@ use mio::net::{TcpListener, TcpStream}; use mio::{Events, Interest, Poll, Token, Waker}; mod util; -use util::{any_local_address, init, init_with_poll, temp_file}; +use util::{any_local_address, init, init_with_poll}; const ID1: Token = Token(1); const WAKE_TOKEN: Token = Token(10); @@ -109,6 +109,7 @@ fn issue_1205() { #[cfg(unix)] fn issue_1403() { use mio::net::UnixDatagram; + use util::temp_file; init();