Skip to content

Commit 050faa3

Browse files
committed
Fix _overlapped segfault and missing _winapi constants
- Fix from_windows_err using new_exception_empty on OSError subclasses (ConnectionRefusedError, ConnectionAbortedError), which caused segfault in release builds due to debug_assert on type size mismatch - Move ConnectPipe from instance method to module-level function - Add Destructor for Overlapped to cancel pending I/O on object cleanup - Add NMPWAIT_NOWAIT, NMPWAIT_USE_DEFAULT_WAIT, NMPWAIT_WAIT_FOREVER constants to _winapi
1 parent adb7a91 commit 050faa3

File tree

2 files changed

+77
-40
lines changed

2 files changed

+77
-40
lines changed

crates/stdlib/src/overlapped.rs

Lines changed: 76 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ mod _overlapped {
1414
convert::{ToPyException, ToPyObject},
1515
function::OptionalArg,
1616
protocol::PyBuffer,
17-
types::Constructor,
17+
types::{Constructor, Destructor},
1818
};
1919
use windows_sys::Win32::{
2020
Foundation::{self, GetLastError, HANDLE},
@@ -235,14 +235,8 @@ mod _overlapped {
235235
}
236236

237237
fn from_windows_err(err: u32, vm: &VirtualMachine) -> PyBaseExceptionRef {
238-
use Foundation::{ERROR_CONNECTION_ABORTED, ERROR_CONNECTION_REFUSED};
239238
debug_assert_ne!(err, 0, "call errno_err instead");
240-
let exc = match err {
241-
ERROR_CONNECTION_REFUSED => vm.ctx.exceptions.connection_refused_error,
242-
ERROR_CONNECTION_ABORTED => vm.ctx.exceptions.connection_aborted_error,
243-
err => return std::io::Error::from_raw_os_error(err as i32).to_pyexception(vm),
244-
};
245-
vm.new_exception_empty(exc.to_owned())
239+
std::io::Error::from_raw_os_error(err as i32).to_pyexception(vm)
246240
}
247241

248242
fn HasOverlappedIoCompleted(overlapped: &OVERLAPPED) -> bool {
@@ -383,7 +377,7 @@ mod _overlapped {
383377
}
384378
}
385379

386-
#[pyclass(with(Constructor))]
380+
#[pyclass(with(Constructor, Destructor))]
387381
impl Overlapped {
388382
#[pygetset]
389383
fn address(&self, _vm: &VirtualMachine) -> usize {
@@ -438,7 +432,6 @@ mod _overlapped {
438432
use windows_sys::Win32::Foundation::{
439433
ERROR_BROKEN_PIPE, ERROR_IO_PENDING, ERROR_MORE_DATA, ERROR_SUCCESS,
440434
};
441-
use windows_sys::Win32::System::IO::GetOverlappedResult;
442435

443436
let mut inner = zelf.inner.lock();
444437
let wait = wait.unwrap_or(false);
@@ -454,7 +447,7 @@ mod _overlapped {
454447
// Get the result
455448
let mut transferred: u32 = 0;
456449
let ret = unsafe {
457-
GetOverlappedResult(
450+
windows_sys::Win32::System::IO::GetOverlappedResult(
458451
inner.handle,
459452
&inner.overlapped,
460453
&mut transferred,
@@ -1190,35 +1183,6 @@ mod _overlapped {
11901183
}
11911184
}
11921185

1193-
// ConnectPipe - this is a static method that returns a handle
1194-
#[pymethod]
1195-
fn ConnectPipe(address: String, vm: &VirtualMachine) -> PyResult<isize> {
1196-
use windows_sys::Win32::Storage::FileSystem::{
1197-
CreateFileW, FILE_FLAG_OVERLAPPED, FILE_GENERIC_READ, FILE_GENERIC_WRITE,
1198-
OPEN_EXISTING,
1199-
};
1200-
1201-
let address_wide: Vec<u16> = address.encode_utf16().chain(std::iter::once(0)).collect();
1202-
1203-
let handle = unsafe {
1204-
CreateFileW(
1205-
address_wide.as_ptr(),
1206-
FILE_GENERIC_READ | FILE_GENERIC_WRITE,
1207-
0,
1208-
std::ptr::null(),
1209-
OPEN_EXISTING,
1210-
FILE_FLAG_OVERLAPPED,
1211-
std::ptr::null_mut(),
1212-
)
1213-
};
1214-
1215-
if handle == windows_sys::Win32::Foundation::INVALID_HANDLE_VALUE {
1216-
return Err(vm.new_last_os_error());
1217-
}
1218-
1219-
Ok(handle as isize)
1220-
}
1221-
12221186
// WSASendTo
12231187
#[pymethod]
12241188
fn WSASendTo(
@@ -1508,6 +1472,78 @@ mod _overlapped {
15081472
}
15091473
}
15101474

1475+
impl Destructor for Overlapped {
1476+
fn del(zelf: &Py<Self>, _vm: &VirtualMachine) -> PyResult<()> {
1477+
use windows_sys::Win32::System::IO::{CancelIoEx, GetOverlappedResult};
1478+
1479+
let mut inner = zelf.inner.lock();
1480+
let olderr = unsafe { GetLastError() };
1481+
1482+
// Cancel pending I/O and wait for completion
1483+
if !HasOverlappedIoCompleted(&inner.overlapped)
1484+
&& !matches!(
1485+
inner.data,
1486+
OverlappedData::None | OverlappedData::NotStarted
1487+
)
1488+
{
1489+
let cancelled = unsafe { CancelIoEx(inner.handle, &inner.overlapped) } != 0;
1490+
1491+
if cancelled {
1492+
// Wait for the cancellation to complete
1493+
let mut transferred: u32 = 0;
1494+
unsafe {
1495+
GetOverlappedResult(
1496+
inner.handle,
1497+
&inner.overlapped,
1498+
&mut transferred,
1499+
1, // bWait = TRUE
1500+
)
1501+
};
1502+
}
1503+
}
1504+
1505+
// Close the event handle
1506+
if !inner.overlapped.hEvent.is_null() {
1507+
unsafe {
1508+
Foundation::CloseHandle(inner.overlapped.hEvent);
1509+
}
1510+
inner.overlapped.hEvent = std::ptr::null_mut();
1511+
}
1512+
1513+
// Restore last error
1514+
unsafe { Foundation::SetLastError(olderr) };
1515+
1516+
Ok(())
1517+
}
1518+
}
1519+
1520+
#[pyfunction]
1521+
fn ConnectPipe(address: String, vm: &VirtualMachine) -> PyResult<isize> {
1522+
use windows_sys::Win32::Storage::FileSystem::{
1523+
CreateFileW, FILE_FLAG_OVERLAPPED, FILE_GENERIC_READ, FILE_GENERIC_WRITE, OPEN_EXISTING,
1524+
};
1525+
1526+
let address_wide: Vec<u16> = address.encode_utf16().chain(std::iter::once(0)).collect();
1527+
1528+
let handle = unsafe {
1529+
CreateFileW(
1530+
address_wide.as_ptr(),
1531+
FILE_GENERIC_READ | FILE_GENERIC_WRITE,
1532+
0,
1533+
std::ptr::null(),
1534+
OPEN_EXISTING,
1535+
FILE_FLAG_OVERLAPPED,
1536+
std::ptr::null_mut(),
1537+
)
1538+
};
1539+
1540+
if handle == windows_sys::Win32::Foundation::INVALID_HANDLE_VALUE {
1541+
return Err(vm.new_last_os_error());
1542+
}
1543+
1544+
Ok(handle as isize)
1545+
}
1546+
15111547
#[pyfunction]
15121548
fn CreateIoCompletionPort(
15131549
handle: isize,

crates/vm/src/stdlib/winapi.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,7 @@ mod _winapi {
9494
SEC_LARGE_PAGES, SEC_NOCACHE, SEC_RESERVE, SEC_WRITECOMBINE,
9595
},
9696
Pipes::{
97+
NMPWAIT_NOWAIT, NMPWAIT_USE_DEFAULT_WAIT, NMPWAIT_WAIT_FOREVER,
9798
PIPE_READMODE_MESSAGE, PIPE_TYPE_MESSAGE, PIPE_UNLIMITED_INSTANCES, PIPE_WAIT,
9899
},
99100
SystemServices::LOCALE_NAME_MAX_LENGTH,

0 commit comments

Comments
 (0)