Skip to content

Commit 0681aa6

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 6031139 commit 0681aa6

File tree

2 files changed

+49
-10
lines changed

2 files changed

+49
-10
lines changed

src/platform/windows/aliased_cell.rs

+13
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,19 @@ impl<T> AliasedCell<T> {
105105
&mut self.inner
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

+36-10
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`,
@@ -466,7 +478,7 @@ impl MessageReader {
466478
/// and the caller should not attempt waiting for completion.
467479
fn issue_async_cancel(&mut self) {
468480
unsafe {
469-
let status = kernel32::CancelIoEx(self.handle.as_raw(),
481+
let status = kernel32::CancelIoEx(self.async.as_ref().unwrap().alias().handle.as_raw(),
470482
self.async.as_mut().unwrap().alias_mut().ov.deref_mut());
471483

472484
if status == winapi::FALSE {
@@ -486,7 +498,9 @@ impl MessageReader {
486498
// and the caller should not attempt to wait for completion.
487499
assert!(GetLastError() == winapi::ERROR_NOT_FOUND);
488500

489-
self.read_buf = self.async.take().unwrap().into_inner().buf;
501+
let async_data = self.async.take().unwrap().into_inner();
502+
self.handle = async_data.handle;
503+
self.read_buf = async_data.buf;
490504
}
491505
}
492506
}
@@ -543,14 +557,15 @@ impl MessageReader {
543557

544558
// issue the read to the buffer, at the current length offset
545559
self.async = Some(AliasedCell::new(AsyncData {
560+
handle: self.handle.take(),
546561
ov: Box::new(mem::zeroed()),
547562
buf: mem::replace(&mut self.read_buf, vec![]),
548563
}));
549564
let mut bytes_read: u32 = 0;
550565
let ok = {
551566
let async_data = self.async.as_mut().unwrap().alias_mut();
552567
let remaining_buf = &mut async_data.buf[buf_len..];
553-
kernel32::ReadFile(self.handle.as_raw(),
568+
kernel32::ReadFile(async_data.handle.as_raw(),
554569
remaining_buf.as_mut_ptr() as LPVOID,
555570
remaining_buf.len() as u32,
556571
&mut bytes_read,
@@ -593,11 +608,18 @@ impl MessageReader {
593608
},
594609
Err(winapi::ERROR_BROKEN_PIPE) => {
595610
win32_trace!("[$ {:?}] BROKEN_PIPE straight from ReadFile", self.handle);
596-
self.read_buf = self.async.take().unwrap().into_inner().buf;
611+
612+
let async_data = self.async.take().unwrap().into_inner();
613+
self.handle = async_data.handle;
614+
self.read_buf = async_data.buf;
615+
597616
Err(WinError::ChannelClosed)
598617
},
599618
Err(err) => {
600-
self.read_buf = self.async.take().unwrap().into_inner().buf;
619+
let async_data = self.async.take().unwrap().into_inner();
620+
self.handle = async_data.handle;
621+
self.read_buf = async_data.buf;
622+
601623
Err(WinError::from_system(err, "ReadFile"))
602624
},
603625
}
@@ -621,12 +643,13 @@ impl MessageReader {
621643
/// between receiving the completion notification from the kernel
622644
/// and invoking this method.
623645
unsafe fn notify_completion(&mut self, io_result: Result<(), WinError>) -> Result<(), WinError> {
624-
win32_trace!("[$ {:?}] notify_completion", self.handle);
646+
win32_trace!("[$ {:?}] notify_completion", self.async.as_ref().unwrap().alias().handle);
625647

626648
// Regardless whether the kernel reported success or error,
627649
// it doesn't have an async read operation in flight at this point anymore.
628650
// (And it's safe again to access the `async` data.)
629651
let async_data = self.async.take().unwrap().into_inner();
652+
self.handle = async_data.handle;
630653
let ov = async_data.ov;
631654
self.read_buf = async_data.buf;
632655

@@ -677,7 +700,7 @@ impl MessageReader {
677700
BlockingMode::Blocking => winapi::TRUE,
678701
BlockingMode::Nonblocking => winapi::FALSE,
679702
};
680-
let ok = kernel32::GetOverlappedResult(self.handle.as_raw(),
703+
let ok = kernel32::GetOverlappedResult(self.async.as_ref().unwrap().alias().handle.as_raw(),
681704
self.async.as_mut().unwrap().alias_mut().ov.deref_mut(),
682705
&mut nbytes,
683706
block);
@@ -1405,7 +1428,10 @@ impl OsIpcReceiverSet {
14051428

14061429
// Find the matching receiver
14071430
let (reader_index, _) = self.readers.iter().enumerate()
1408-
.find(|&(_, ref reader)| reader.handle.as_raw() as winapi::ULONG_PTR == completion_key)
1431+
.find(|&(_, ref reader)| {
1432+
let raw_handle = reader.async.as_ref().unwrap().alias().handle.as_raw();
1433+
raw_handle as winapi::ULONG_PTR == completion_key
1434+
})
14091435
.expect("Windows IPC ReceiverSet got notification for a receiver it doesn't know about");
14101436

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

0 commit comments

Comments
 (0)