Skip to content

Commit fac85e5

Browse files
committed
windows: Move handle into AsyncData as well
For the duration of an async read operation, move the pipe handle into the `AliasedCell` along with the other fields used for the async operation. This prevents anything else from messing with the pipe while the async read is in progress; and makes sure the handle and the other fields can never get mismatched. While I'm not sure whether there is any scenario in which such a mismatch could result in undefined behaviour, it's good for general robustness in any case.
1 parent 9a67245 commit fac85e5

File tree

2 files changed

+49
-10
lines changed

2 files changed

+49
-10
lines changed

src/platform/windows/aliased_cell.rs

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,19 @@ impl<T> AliasedCell<T> {
105105
&mut self.value
106106
}
107107

108+
/// Get a shared (immutable) pointer to the inner value.
109+
///
110+
/// With this method it's possible to get an alias
111+
/// while only holding a shared reference to the `AliasedCell`.
112+
///
113+
/// Since all the unsafe aliases are untracked,
114+
/// it's up to the callers to make sure no shared aliases are used
115+
/// while the data might actually be mutated elsewhere
116+
/// through some outstanding mutable aliases.
117+
pub unsafe fn alias(&self) -> &T {
118+
&self.inner
119+
}
120+
108121
/// Move out the wrapped value, making it accessible from safe code again.
109122
pub unsafe fn into_inner(self) -> T {
110123
mem::forget(self.drop_bomb);

src/platform/windows/mod.rs

Lines changed: 36 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -340,6 +340,9 @@ impl WinHandle {
340340
/// Helper struct for all data being aliased by the kernel during async reads.
341341
#[derive(Debug)]
342342
struct AsyncData {
343+
/// File handle of the pipe on which the async operation is performed.
344+
handle: WinHandle,
345+
343346
/// Meta-data for this async read operation, filled by the kernel.
344347
///
345348
/// This must be on the heap, in order for its memory location --
@@ -362,12 +365,21 @@ struct AsyncData {
362365
#[derive(Debug)]
363366
struct MessageReader {
364367
/// The pipe read handle.
368+
///
369+
/// Note: this is only set while no async read operation
370+
/// is currently in progress with the kernel.
371+
/// When an async read is in progress,
372+
/// it is moved into the `async` sub-structure (see below)
373+
/// along with the other fields used for the async operation,
374+
/// to make sure they all stay in sync,
375+
/// and nothing else can meddle with the the pipe
376+
/// until the operation is completed.
365377
handle: WinHandle,
366378

367379
/// Buffer for outstanding data, that has been received but not yet processed.
368380
///
369-
/// Note: this is only set while no async read operation
370-
/// is currently in progress with the kernel.
381+
/// Note: just like `handle` above,
382+
/// this is only set while no async read is in progress.
371383
/// When an async read is in progress,
372384
/// the receive buffer is aliased by the kernel;
373385
/// so we need to temporarily move it into an `AliasedCell`,
@@ -460,7 +472,7 @@ impl MessageReader {
460472
/// and the caller should not attempt waiting for completion.
461473
fn issue_async_cancel(&mut self) {
462474
unsafe {
463-
let status = kernel32::CancelIoEx(self.handle.as_raw(),
475+
let status = kernel32::CancelIoEx(self.async.as_ref().unwrap().alias().handle.as_raw(),
464476
self.async.as_mut().unwrap().alias_mut().ov.deref_mut());
465477

466478
if status == winapi::FALSE {
@@ -480,7 +492,9 @@ impl MessageReader {
480492
// and the caller should not attempt to wait for completion.
481493
assert!(GetLastError() == winapi::ERROR_NOT_FOUND);
482494

483-
self.read_buf = self.async.take().unwrap().into_inner().buf;
495+
let async_data = self.async.take().unwrap().into_inner();
496+
self.handle = async_data.handle;
497+
self.read_buf = async_data.buf;
484498
}
485499
}
486500
}
@@ -537,14 +551,15 @@ impl MessageReader {
537551

538552
// issue the read to the buffer, at the current length offset
539553
self.async = Some(AliasedCell::new(AsyncData {
554+
handle: self.handle.take(),
540555
ov: Box::new(mem::zeroed()),
541556
buf: mem::replace(&mut self.read_buf, vec![]),
542557
}));
543558
let mut bytes_read: u32 = 0;
544559
let ok = {
545560
let async_data = self.async.as_mut().unwrap().alias_mut();
546561
let remaining_buf = &mut async_data.buf[buf_len..];
547-
kernel32::ReadFile(self.handle.as_raw(),
562+
kernel32::ReadFile(async_data.handle.as_raw(),
548563
remaining_buf.as_mut_ptr() as LPVOID,
549564
remaining_buf.len() as u32,
550565
&mut bytes_read,
@@ -587,11 +602,18 @@ impl MessageReader {
587602
},
588603
Err(winapi::ERROR_BROKEN_PIPE) => {
589604
win32_trace!("[$ {:?}] BROKEN_PIPE straight from ReadFile", self.handle);
590-
self.read_buf = self.async.take().unwrap().into_inner().buf;
605+
606+
let async_data = self.async.take().unwrap().into_inner();
607+
self.handle = async_data.handle;
608+
self.read_buf = async_data.buf;
609+
591610
Err(WinError::ChannelClosed)
592611
},
593612
Err(err) => {
594-
self.read_buf = self.async.take().unwrap().into_inner().buf;
613+
let async_data = self.async.take().unwrap().into_inner();
614+
self.handle = async_data.handle;
615+
self.read_buf = async_data.buf;
616+
595617
Err(WinError::from_system(err, "ReadFile"))
596618
},
597619
}
@@ -615,12 +637,13 @@ impl MessageReader {
615637
/// between receiving the completion notification from the kernel
616638
/// and invoking this method.
617639
unsafe fn notify_completion(&mut self, io_result: Result<(), WinError>) -> Result<(), WinError> {
618-
win32_trace!("[$ {:?}] notify_completion", self.handle);
640+
win32_trace!("[$ {:?}] notify_completion", self.async.as_ref().unwrap().alias().handle);
619641

620642
// Regardless whether the kernel reported success or error,
621643
// it doesn't have an async read operation in flight at this point anymore.
622644
// (And it's safe again to access the `async` data.)
623645
let async_data = self.async.take().unwrap().into_inner();
646+
self.handle = async_data.handle;
624647
let ov = async_data.ov;
625648
self.read_buf = async_data.buf;
626649

@@ -671,7 +694,7 @@ impl MessageReader {
671694
BlockingMode::Blocking => winapi::TRUE,
672695
BlockingMode::Nonblocking => winapi::FALSE,
673696
};
674-
let ok = kernel32::GetOverlappedResult(self.handle.as_raw(),
697+
let ok = kernel32::GetOverlappedResult(self.async.as_ref().unwrap().alias().handle.as_raw(),
675698
self.async.as_mut().unwrap().alias_mut().ov.deref_mut(),
676699
&mut nbytes,
677700
block);
@@ -1399,7 +1422,10 @@ impl OsIpcReceiverSet {
13991422

14001423
// Find the matching receiver
14011424
let (reader_index, _) = self.readers.iter().enumerate()
1402-
.find(|&(_, ref reader)| reader.handle.as_raw() as winapi::ULONG_PTR == completion_key)
1425+
.find(|&(_, ref reader)| {
1426+
let raw_handle = reader.async.as_ref().unwrap().alias().handle.as_raw();
1427+
raw_handle as winapi::ULONG_PTR == completion_key
1428+
})
14031429
.expect("Windows IPC ReceiverSet got notification for a receiver it doesn't know about");
14041430

14051431
// Remove the entry from the set for now -- we will re-add it later,

0 commit comments

Comments
 (0)