Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
a5ac299
Convert host_env Windows path/argv params from raw *const u16 to &Wid…
youknowone May 16, 2026
cea48cc
Migrate remaining winapi raw u16 pointer signatures to typed references
youknowone May 16, 2026
25a9d40
Migrate winreg pub unsafe fn string parameters to typed references
youknowone May 16, 2026
0acdcad
Add ToPyException impls for host_env error types (PyPy wrap_oserror a…
youknowone May 16, 2026
dc57418
Add CheckLibcResult helper and apply to socket/fcntl/shm/posix_wasi
youknowone May 16, 2026
2d4be2c
Add Win32 BOOL/HANDLE check helpers; apply check helpers across host_env
youknowone May 16, 2026
592e8b4
Apply Win32/libc check helpers to overlapped/testconsole/os.rs
youknowone May 16, 2026
86055d2
Apply Win32 check helpers to winapi.rs (partial)
youknowone May 16, 2026
fe71c58
Apply Win32 check helpers across more winapi.rs functions
youknowone May 16, 2026
a7c567a
Apply Win32 check helpers to nt.rs (partial)
youknowone May 16, 2026
5329cc5
Add CheckWin32Sentinel helper; apply to nt.rs INVALID_HANDLE_VALUE/IN…
youknowone May 16, 2026
f1532e2
Add OwnedHandle / HandleToOwned helper; apply to mmap create_named_ma…
youknowone May 16, 2026
e768278
Use OwnedHandle RAII in nt::pipe to eliminate manual cleanup on error…
youknowone May 16, 2026
b730f7e
Use OwnedHandle in nt::chmod_follow; hoist HandleToOwned import
youknowone May 16, 2026
67ece5b
Drop rustix dependency from vm crate
youknowone May 17, 2026
a61d9bd
Fix CI failures: cross-platform regressions
youknowone May 19, 2026
3320c2a
Fix CI failures: cfg gates and unused imports
youknowone May 19, 2026
e9ec6e8
Fix CI failures: rustfmt and windows unused import
youknowone May 19, 2026
ba3f4fa
Push remaining libc/extern callsites from vm into host_env
youknowone May 19, 2026
45c83dd
Move time tz state and winsound FFI into host_env
youknowone May 19, 2026
49c13f8
Migrate unsetenv to host_env::nt::wputenv; rustfmt
youknowone May 20, 2026
61e0fd4
Address PR review comments
youknowone May 20, 2026
783c6b5
Fix CI failures and address review follow-ups
youknowone May 20, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 1 addition & 2 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 0 additions & 1 deletion Lib/test/test_format.py
Original file line number Diff line number Diff line change
Expand Up @@ -423,7 +423,6 @@ def test_non_ascii(self):
self.assertEqual(format(1+2j, "\u2007^8"), "\u2007(1+2j)\u2007")
self.assertEqual(format(0j, "\u2007^4"), "\u20070j\u2007")

@unittest.expectedFailureIfWindows("TODO: RUSTPYTHON; AssertionError: ',' not found in '123456789'")
def test_locale(self):
try:
oldloc = locale.setlocale(locale.LC_ALL)
Expand Down
2 changes: 0 additions & 2 deletions Lib/test/test_types.py
Original file line number Diff line number Diff line change
Expand Up @@ -431,7 +431,6 @@ def test(i, format_spec, result):
test(123456, "1=20", '11111111111111123456')
test(123456, "*=20", '**************123456')

@unittest.expectedFailureIfWindows("TODO: RUSTPYTHON; AssertionError: '1,234.57' != '1234.57'")
@run_with_locale('LC_NUMERIC', 'en_US.UTF8', '')
def test_float__format__locale(self):
# test locale support for __format__ code 'n'
Expand All @@ -441,7 +440,6 @@ def test_float__format__locale(self):
self.assertEqual(locale.format_string('%g', x, grouping=True), format(x, 'n'))
self.assertEqual(locale.format_string('%.10g', x, grouping=True), format(x, '.10n'))

@unittest.expectedFailureIfWindows("TODO: RUSTPYTHON; AssertionError: '123,456,789,012,345,678,901,234,567,890' != '123456789012345678901234567890'")
@run_with_locale('LC_NUMERIC', 'en_US.UTF8', '')
def test_int__format__locale(self):
# test locale support for __format__ code 'n' for integers
Expand Down
1 change: 1 addition & 0 deletions crates/host_env/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ license.workspace = true
rustpython-wtf8 = { workspace = true }

bitflags = { workspace = true }
getrandom = { workspace = true }
libc = { workspace = true }
num-traits = { workspace = true }
parking_lot = { workspace = true }
Expand Down
13 changes: 13 additions & 0 deletions crates/host_env/src/errno.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,18 @@
// spell-checker:disable

/// Return the platform `strerror(errno)` message as an owned `String`.
/// Returns `None` when the runtime gives no description for `errno`.
#[cfg(any(unix, windows))]
#[must_use]
pub fn strerror_string(errno: i32) -> Option<String> {
let ptr = unsafe { libc::strerror(errno) };
if ptr.is_null() {
return None;
}
let s = unsafe { core::ffi::CStr::from_ptr(ptr) }.to_string_lossy();
Some(s.into_owned())
}

#[cfg(any(unix, windows, target_os = "wasi"))]
pub mod errors {
pub use libc::*;
Expand Down
46 changes: 10 additions & 36 deletions crates/host_env/src/fcntl.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,17 +3,14 @@ use std::io;
#[cfg(unix)]
use std::os::fd::BorrowedFd;

use crate::os::CheckLibcResult;

pub fn normalize_ioctl_request(request: i64) -> libc::c_ulong {
(request as u32) as libc::c_ulong
}

pub fn fcntl_int(fd: i32, cmd: i32, arg: i32) -> io::Result<i32> {
let ret = unsafe { libc::fcntl(fd, cmd, arg) };
if ret < 0 {
Err(io::Error::last_os_error())
} else {
Ok(ret)
}
unsafe { libc::fcntl(fd, cmd, arg) }.check_libc_neg()
}

pub fn validate_fd(fd: i32) -> io::Result<()> {
Expand Down Expand Up @@ -56,12 +53,7 @@ pub fn set_blocking(fd: BorrowedFd<'_>, blocking: bool) -> io::Result<()> {
}

pub fn fcntl_with_bytes(fd: i32, cmd: i32, arg: &mut [u8]) -> io::Result<i32> {
let ret = unsafe { libc::fcntl(fd, cmd, arg.as_mut_ptr()) };
if ret < 0 {
Err(io::Error::last_os_error())
} else {
Ok(ret)
}
unsafe { libc::fcntl(fd, cmd, arg.as_mut_ptr()) }.check_libc_neg()
}

/// # Safety
Expand All @@ -73,31 +65,16 @@ pub unsafe fn ioctl_ptr(
request: libc::c_ulong,
arg: *mut libc::c_void,
) -> io::Result<i32> {
let ret = unsafe { libc::ioctl(fd, request as _, arg) };
if ret < 0 {
Err(io::Error::last_os_error())
} else {
Ok(ret)
}
unsafe { libc::ioctl(fd, request as _, arg) }.check_libc_neg()
}

pub fn ioctl_int(fd: i32, request: libc::c_ulong, arg: i32) -> io::Result<i32> {
let ret = unsafe { libc::ioctl(fd, request as _, arg) };
if ret < 0 {
Err(io::Error::last_os_error())
} else {
Ok(ret)
}
unsafe { libc::ioctl(fd, request as _, arg) }.check_libc_neg()
}

#[cfg(not(any(target_os = "wasi", target_os = "redox")))]
pub fn flock(fd: i32, operation: i32) -> io::Result<i32> {
let ret = unsafe { libc::flock(fd, operation) };
if ret < 0 {
Err(io::Error::last_os_error())
} else {
Ok(ret)
}
unsafe { libc::flock(fd, operation) }.check_libc_neg()
}

#[cfg(not(any(target_os = "wasi", target_os = "redox")))]
Expand Down Expand Up @@ -137,7 +114,7 @@ pub fn lockf(fd: i32, cmd: i32, len: i64, start: i64, whence: i32) -> Result<i32
..unsafe { core::mem::zeroed() }
};

let ret = unsafe {
unsafe {
libc::fcntl(
fd,
if (cmd & libc::LOCK_NB) != 0 {
Expand All @@ -147,10 +124,7 @@ pub fn lockf(fd: i32, cmd: i32, len: i64, start: i64, whence: i32) -> Result<i32
},
&lock,
)
};
if ret < 0 {
Err(LockfError::Io(io::Error::last_os_error()))
} else {
Ok(ret)
}
.check_libc_neg()
.map_err(LockfError::Io)
}
10 changes: 10 additions & 0 deletions crates/host_env/src/io.rs
Original file line number Diff line number Diff line change
Expand Up @@ -252,3 +252,13 @@ pub fn write_once(fd: crt_fd::Borrowed<'_>, buf: &[u8]) -> io::Result<usize> {
pub fn close_owned_fd(fd: crt_fd::Owned) -> io::Result<()> {
crt_fd::close(fd)
}

/// Async-signal-safe raw write to the platform stderr file descriptor.
/// Avoids `std::io::stderr()` locking so it is safe to call from fork
/// children and signal handlers.
#[cfg(unix)]
pub fn write_stderr_raw(buf: &[u8]) {
unsafe {
let _ = libc::write(libc::STDERR_FILENO, buf.as_ptr().cast(), buf.len());
}
}
2 changes: 1 addition & 1 deletion crates/host_env/src/io_unsupported.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ const O_TRUNC: i32 = 0x0400;
const O_EXCL: i32 = 0x0800;

bitflags::bitflags! {
#[derive(Copy, Clone, Debug, PartialEq)]
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub struct FileMode: u8 {
const CREATED = 0b0001;
const READABLE = 0b0010;
Expand Down
2 changes: 2 additions & 0 deletions crates/host_env/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -83,4 +83,6 @@ pub mod winapi;
#[cfg(windows)]
pub mod winreg;
#[cfg(windows)]
pub mod winsound;
#[cfg(windows)]
pub mod wmi;
48 changes: 24 additions & 24 deletions crates/host_env/src/mmap.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,14 @@

use std::io;

#[cfg(windows)]
use crate::windows::{CheckWin32Bool, HandleToOwned};
#[cfg(unix)]
use crate::{crt_fd, fileutils, posix};
use memmap2::{Mmap, MmapMut, MmapOptions};
#[cfg(windows)]
use std::os::windows::io::{AsRawHandle, IntoRawHandle};
#[cfg(windows)]
use windows_sys::Win32::{
Foundation::{
CloseHandle, DUPLICATE_SAME_ACCESS, DuplicateHandle, GetLastError, HANDLE,
Expand Down Expand Up @@ -131,7 +135,7 @@ impl Drop for NamedMmap {
#[cfg(windows)]
pub fn duplicate_handle(handle: Handle) -> io::Result<Handle> {
let mut new_handle: Handle = INVALID_HANDLE;
let result = unsafe {
unsafe {
DuplicateHandle(
GetCurrentProcess(),
handle,
Expand All @@ -141,12 +145,9 @@ pub fn duplicate_handle(handle: Handle) -> io::Result<Handle> {
0,
DUPLICATE_SAME_ACCESS,
)
};
if result == 0 {
Err(io::Error::last_os_error())
} else {
Ok(new_handle)
}
.check_win32_bool()?;
Ok(new_handle)
}

#[cfg(windows)]
Expand Down Expand Up @@ -187,13 +188,9 @@ pub fn is_invalid_handle_value(handle: isize) -> bool {

#[cfg(windows)]
pub fn extend_file(handle: Handle, size: i64) -> io::Result<()> {
if unsafe { SetFilePointerEx(handle, size, core::ptr::null_mut(), FILE_BEGIN) } == 0 {
return Err(io::Error::last_os_error());
}
if unsafe { SetEndOfFile(handle) } == 0 {
return Err(io::Error::last_os_error());
}
Ok(())
unsafe { SetFilePointerEx(handle, size, core::ptr::null_mut(), FILE_BEGIN) }
.check_win32_bool()?;
unsafe { SetEndOfFile(handle) }.check_win32_bool()
}

#[cfg(unix)]
Expand All @@ -210,11 +207,7 @@ pub fn close_handle(handle: Handle) {

#[cfg(windows)]
pub fn flush_view(ptr: *const core::ffi::c_void, size: usize) -> io::Result<()> {
if unsafe { FlushViewOfFile(ptr, size) } == 0 {
Err(io::Error::last_os_error())
} else {
Ok(())
}
unsafe { FlushViewOfFile(ptr, size) }.check_win32_bool()
}

#[cfg(windows)]
Expand Down Expand Up @@ -252,21 +245,28 @@ pub fn create_named_mapping(
size_lo,
tag_wide.as_ptr(),
)
};
if map_handle.is_null() {
return Err(io::Error::last_os_error());
}
.into_owned()
.ok_or_else(io::Error::last_os_error)?;

let off_hi = (offset as u64 >> 32) as u32;
let off_lo = offset as u32;
let view = unsafe { MapViewOfFile(map_handle, desired_access, off_hi, off_lo, map_size) };
let view = unsafe {
MapViewOfFile(
map_handle.as_raw_handle() as Handle,
desired_access,
off_hi,
off_lo,
map_size,
)
};
if view.Value.is_null() {
unsafe { CloseHandle(map_handle) };
// `map_handle` is closed automatically when dropped on this error path.
return Err(io::Error::last_os_error());
}

Ok(NamedMmap {
map_handle,
map_handle: map_handle.into_raw_handle() as Handle,
view_ptr: view.Value as *mut u8,
len: map_size,
})
Expand Down
31 changes: 7 additions & 24 deletions crates/host_env/src/msvcrt.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ use alloc::{string::String, vec::Vec};
use std::io;

use crate::crt_fd;
use crate::os::CheckLibcResult;
use windows_sys::Win32::System::Diagnostics::Debug;

pub type ErrorMode = u32;
Expand Down Expand Up @@ -89,39 +90,21 @@ pub fn kbhit() -> i32 {
}

pub fn locking(fd: i32, mode: i32, nbytes: i64) -> io::Result<()> {
let ret = unsafe { suppress_iph!(_locking(fd, mode, nbytes)) };
if ret == -1 {
Err(io::Error::last_os_error())
} else {
Ok(())
}
unsafe { suppress_iph!(_locking(fd, mode, nbytes)) }.check_libc_neg()?;
Ok(())
}

pub fn heapmin() -> io::Result<()> {
let ret = unsafe { suppress_iph!(_heapmin()) };
if ret == -1 {
Err(io::Error::last_os_error())
} else {
Ok(())
}
unsafe { suppress_iph!(_heapmin()) }.check_libc_neg()?;
Ok(())
}

pub fn setmode(fd: crt_fd::Borrowed<'_>, flags: i32) -> io::Result<i32> {
let ret = unsafe { suppress_iph!(_setmode(fd, flags)) };
if ret == -1 {
Err(io::Error::last_os_error())
} else {
Ok(ret)
}
unsafe { suppress_iph!(_setmode(fd, flags)) }.check_libc_neg()
}

pub fn open_osfhandle(handle: isize, flags: i32) -> io::Result<i32> {
let ret = unsafe { suppress_iph!(libc::open_osfhandle(handle, flags)) };
if ret == -1 {
Err(io::Error::last_os_error())
} else {
Ok(ret)
}
unsafe { suppress_iph!(libc::open_osfhandle(handle, flags)) }.check_libc_neg()
}

pub fn get_error_mode() -> u32 {
Expand Down
10 changes: 4 additions & 6 deletions crates/host_env/src/multiprocessing.rs
Original file line number Diff line number Diff line change
Expand Up @@ -159,13 +159,11 @@ impl SemHandle {
#[cfg(windows)]
impl SemHandle {
pub fn create(value: i32, maxvalue: i32) -> io::Result<Self> {
use crate::windows::CheckWin32Handle;
let handle =
unsafe { CreateSemaphoreW(core::ptr::null(), value, maxvalue, core::ptr::null()) };
if handle == 0 as HANDLE {
Err(io::Error::last_os_error())
} else {
Ok(Self { raw: handle })
}
unsafe { CreateSemaphoreW(core::ptr::null(), value, maxvalue, core::ptr::null()) }
.check_nonnull()?;
Ok(Self { raw: handle })
}

#[inline]
Expand Down
Loading
Loading