Skip to content

Commit e316b21

Browse files
committed
Replace offset constants with methods in Windows NamedPipe
1 parent 9e13732 commit e316b21

File tree

1 file changed

+46
-18
lines changed

1 file changed

+46
-18
lines changed

src/sys/windows/named_pipe.rs

Lines changed: 46 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ use miow::iocp::{CompletionPort, CompletionStatus};
1111
use miow::pipe;
1212
use winapi::shared::winerror::{ERROR_BROKEN_PIPE, ERROR_PIPE_LISTENING};
1313
use winapi::um::ioapiset::CancelIoEx;
14-
use winapi::um::minwinbase::OVERLAPPED_ENTRY;
14+
use winapi::um::minwinbase::{OVERLAPPED, OVERLAPPED_ENTRY};
1515

1616
use crate::event::Source;
1717
use crate::sys::windows::{Event, Overlapped};
@@ -70,35 +70,64 @@ pub struct NamedPipe {
7070
/// constants depend on it, see the `offset_constants` test.
7171
#[repr(C)]
7272
struct Inner {
73+
// NOTE: careful modifying the order of these three fields, the `ptr_from_*`
74+
// methods depend on the layout!
7375
connect: Overlapped,
7476
read: Overlapped,
7577
write: Overlapped,
78+
// END NOTE.
7679
handle: pipe::NamedPipe,
7780
connecting: AtomicBool,
7881
io: Mutex<Io>,
7982
pool: Mutex<BufferPool>,
8083
}
8184

82-
/// Offsets from a pointer to `Inner` to the `connect`, `read` and `write`
83-
/// fields.
84-
const CONNECT_OFFSET: usize = 0;
85-
const READ_OFFSET: usize = CONNECT_OFFSET + size_of::<Overlapped>(); // `connect` fields.
86-
const WRITE_OFFSET: usize = READ_OFFSET + size_of::<Overlapped>(); // `read` fields.
85+
impl Inner {
86+
/// Converts a pointer to `Inner.connect` to a pointer to `Inner`.
87+
///
88+
/// # Unsafety
89+
///
90+
/// Caller must ensure `ptr` is pointing to `Inner.connect`.
91+
unsafe fn ptr_from_conn_overlapped(ptr: *mut OVERLAPPED) -> *const Inner {
92+
// `connect` is the first field, so the pointer are the same.
93+
ptr.cast()
94+
}
95+
96+
/// Same as [`ptr_from_conn_overlapped`] but for `Inner.read`.
97+
unsafe fn ptr_from_read_overlapped(ptr: *mut OVERLAPPED) -> *const Inner {
98+
// `read` is after `connect: Overlapped`.
99+
(ptr as usize + size_of::<Overlapped>()) as *const Inner
100+
}
101+
102+
/// Same as [`ptr_from_conn_overlapped`] but for `Inner.write`.
103+
unsafe fn ptr_from_write_overlapped(ptr: *mut OVERLAPPED) -> *const Inner {
104+
// `read` is after `connect: Overlapped` and `read: Overlapped`.
105+
(ptr as usize + (2 * size_of::<Overlapped>())) as *const Inner
106+
}
107+
}
87108

88109
#[test]
89-
fn offset_constants() {
110+
fn ptr_from() {
90111
use std::mem::ManuallyDrop;
91112
use std::ptr;
92113

93114
let pipe = unsafe { ManuallyDrop::new(NamedPipe::from_raw_handle(ptr::null_mut())) };
94115
let inner: &Inner = &pipe.inner;
95-
let base = inner as *const Inner as usize;
96-
let connect = &inner.connect as *const Overlapped as usize;
97-
assert_eq!(base + CONNECT_OFFSET, connect);
98-
let read = &inner.read as *const Overlapped as usize;
99-
assert_eq!(base + READ_OFFSET, read);
100-
let write = &inner.write as *const Overlapped as usize;
101-
assert_eq!(base + WRITE_OFFSET, write);
116+
assert_eq!(
117+
inner as *const Inner,
118+
unsafe { Inner::ptr_from_conn_overlapped(&inner.connect as *const _ as *mut OVERLAPPED) },
119+
"`ptr_from_conn_overlapped` incorrect"
120+
);
121+
assert_eq!(
122+
inner as *const Inner,
123+
unsafe { Inner::ptr_from_read_overlapped(&inner.read as *const _ as *mut OVERLAPPED) },
124+
"`ptr_from_read_overlapped` incorrect"
125+
);
126+
assert_eq!(
127+
inner as *const Inner,
128+
unsafe { Inner::ptr_from_write_overlapped(&inner.write as *const _ as *mut OVERLAPPED) },
129+
"`ptr_from_write_overlapped` incorrect"
130+
);
102131
}
103132

104133
struct Io {
@@ -590,8 +619,7 @@ fn connect_done(status: &OVERLAPPED_ENTRY, events: Option<&mut Vec<Event>>) {
590619
// Acquire the `Arc<Inner>`. Note that we should be guaranteed that
591620
// the refcount is available to us due to the `mem::forget` in
592621
// `connect` above.
593-
let me =
594-
unsafe { Arc::from_raw((status.overlapped() as usize - CONNECT_OFFSET) as *mut Inner) };
622+
let me = unsafe { Arc::from_raw(Inner::ptr_from_conn_overlapped(status.overlapped())) };
595623

596624
// Flag ourselves as no longer using the `connect` overlapped instances.
597625
let prev = me.connecting.swap(false, SeqCst);
@@ -617,7 +645,7 @@ fn read_done(status: &OVERLAPPED_ENTRY, events: Option<&mut Vec<Event>>) {
617645
// Acquire the `FromRawArc<Inner>`. Note that we should be guaranteed that
618646
// the refcount is available to us due to the `mem::forget` in
619647
// `schedule_read` above.
620-
let me = unsafe { Arc::from_raw((status.overlapped() as usize - READ_OFFSET) as *mut Inner) };
648+
let me = unsafe { Arc::from_raw(Inner::ptr_from_read_overlapped(status.overlapped())) };
621649

622650
// Move from the `Pending` to `Ok` state.
623651
let mut io = me.io.lock().unwrap();
@@ -649,7 +677,7 @@ fn write_done(status: &OVERLAPPED_ENTRY, events: Option<&mut Vec<Event>>) {
649677
// Acquire the `Arc<Inner>`. Note that we should be guaranteed that
650678
// the refcount is available to us due to the `mem::forget` in
651679
// `schedule_write` above.
652-
let me = unsafe { Arc::from_raw((status.overlapped() as usize - WRITE_OFFSET) as *mut Inner) };
680+
let me = unsafe { Arc::from_raw(Inner::ptr_from_write_overlapped(status.overlapped())) };
653681

654682
// Make the state change out of `Pending`. If we wrote the entire buffer
655683
// then we're writable again and otherwise we schedule another write.

0 commit comments

Comments
 (0)