Skip to content

Commit cda8656

Browse files
committed
Fix Overlapped I/O by boxing OVERLAPPED struct and accept overlapped arg positionally
Two fixes in _winapi: 1. Box the OVERLAPPED struct in OverlappedInner to ensure it stays at a stable heap address. Previously, into_pyobject() moved the struct after ReadFile/WriteFile had given the OS a pointer to it, causing GetOverlappedResult to read stale data (returning err=0 instead of ERROR_MORE_DATA for zero-byte reads on message pipes). 2. Change ReadFile, WriteFile, ConnectNamedPipe overlapped parameter from #[pyarg(named)] to #[pyarg(any)] so it can be passed both positionally and as keyword argument.
1 parent 7b866f6 commit cda8656

File tree

1 file changed

+19
-15
lines changed

1 file changed

+19
-15
lines changed

crates/vm/src/stdlib/_winapi.rs

Lines changed: 19 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -800,7 +800,11 @@ mod _winapi {
800800
}
801801

802802
struct OverlappedInner {
803-
overlapped: windows_sys::Win32::System::IO::OVERLAPPED,
803+
// Box ensures the OVERLAPPED struct stays at a stable heap address
804+
// even when the containing Overlapped Python object is moved during
805+
// into_pyobject(). The OS holds a pointer to this struct for pending
806+
// I/O operations, so it must not be relocated.
807+
overlapped: Box<windows_sys::Win32::System::IO::OVERLAPPED>,
804808
handle: HANDLE,
805809
pending: bool,
806810
completed: bool,
@@ -833,7 +837,7 @@ mod _winapi {
833837

834838
Overlapped {
835839
inner: PyMutex::new(OverlappedInner {
836-
overlapped,
840+
overlapped: Box::new(overlapped),
837841
handle,
838842
pending: false,
839843
completed: false,
@@ -858,7 +862,7 @@ mod _winapi {
858862
let ret = unsafe {
859863
GetOverlappedResult(
860864
inner.handle,
861-
&inner.overlapped,
865+
&*inner.overlapped,
862866
&mut transferred,
863867
if wait { 1 } else { 0 },
864868
)
@@ -913,7 +917,7 @@ mod _winapi {
913917

914918
let mut inner = self.inner.lock();
915919
let ret = if inner.pending {
916-
unsafe { CancelIoEx(inner.handle, &inner.overlapped) }
920+
unsafe { CancelIoEx(inner.handle, &*inner.overlapped) }
917921
} else {
918922
1
919923
};
@@ -958,9 +962,9 @@ mod _winapi {
958962
/// ConnectNamedPipe - Wait for a client to connect to a named pipe
959963
#[derive(FromArgs)]
960964
struct ConnectNamedPipeArgs {
961-
#[pyarg(positional)]
965+
#[pyarg(any)]
962966
handle: WinHandle,
963-
#[pyarg(named, optional)]
967+
#[pyarg(any, optional)]
964968
overlapped: OptionalArg<bool>,
965969
}
966970

@@ -982,7 +986,7 @@ mod _winapi {
982986
unsafe {
983987
windows_sys::Win32::System::Pipes::ConnectNamedPipe(
984988
handle.0,
985-
&mut inner.overlapped,
989+
&mut *inner.overlapped,
986990
)
987991
}
988992
};
@@ -1200,11 +1204,11 @@ mod _winapi {
12001204

12011205
#[derive(FromArgs)]
12021206
struct WriteFileArgs {
1203-
#[pyarg(positional)]
1207+
#[pyarg(any)]
12041208
handle: WinHandle,
1205-
#[pyarg(positional)]
1209+
#[pyarg(any)]
12061210
buffer: crate::function::ArgBytesLike,
1207-
#[pyarg(named, default = false)]
1211+
#[pyarg(any, default = false)]
12081212
overlapped: bool,
12091213
}
12101214

@@ -1233,7 +1237,7 @@ mod _winapi {
12331237
write_buf.as_ptr() as *const _,
12341238
len,
12351239
&mut written,
1236-
&mut inner.overlapped,
1240+
&mut *inner.overlapped,
12371241
)
12381242
};
12391243

@@ -1287,11 +1291,11 @@ mod _winapi {
12871291

12881292
#[derive(FromArgs)]
12891293
struct ReadFileArgs {
1290-
#[pyarg(positional)]
1294+
#[pyarg(any)]
12911295
handle: WinHandle,
1292-
#[pyarg(positional)]
1296+
#[pyarg(any)]
12931297
size: u32,
1294-
#[pyarg(named, default = false)]
1298+
#[pyarg(any, default = false)]
12951299
overlapped: bool,
12961300
}
12971301

@@ -1319,7 +1323,7 @@ mod _winapi {
13191323
read_buf.as_mut_ptr() as *mut _,
13201324
size,
13211325
&mut nread,
1322-
&mut inner.overlapped,
1326+
&mut *inner.overlapped,
13231327
)
13241328
};
13251329

0 commit comments

Comments
 (0)