Skip to content

Commit a0e8df1

Browse files
committed
last crt error
1 parent 96b94cf commit a0e8df1

File tree

3 files changed

+34
-11
lines changed

3 files changed

+34
-11
lines changed

crates/common/src/crt_fd.rs

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,15 @@ pub type Raw = i32;
3535
#[inline]
3636
fn cvt<I: num_traits::PrimInt>(ret: I) -> io::Result<I> {
3737
if ret < I::zero() {
38-
Err(crate::os::last_os_error())
38+
// CRT functions set errno, not GetLastError(), so use last_crt_error on Windows
39+
#[cfg(windows)]
40+
{
41+
Err(crate::os::last_crt_error())
42+
}
43+
#[cfg(not(windows))]
44+
{
45+
Err(crate::os::last_os_error())
46+
}
3947
} else {
4048
Ok(ret)
4149
}
@@ -345,7 +353,8 @@ pub fn as_handle(fd: Borrowed<'_>) -> io::Result<BorrowedHandle<'_>> {
345353
}
346354
let handle = unsafe { suppress_iph!(_get_osfhandle(fd)) };
347355
if handle as HANDLE == INVALID_HANDLE_VALUE {
348-
Err(crate::os::last_os_error())
356+
// _get_osfhandle is a CRT function that sets errno, not GetLastError()
357+
Err(crate::os::last_crt_error())
349358
} else {
350359
Ok(unsafe { BorrowedHandle::borrow_raw(handle as _) })
351360
}

crates/common/src/os.rs

Lines changed: 14 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -24,18 +24,25 @@ pub fn last_os_error() -> io::Error {
2424
let err = io::Error::last_os_error();
2525
// FIXME: probably not ideal, we need a bigger dichotomy between GetLastError and errno
2626
if err.raw_os_error() == Some(0) {
27-
unsafe extern "C" {
28-
fn _get_errno(pValue: *mut i32) -> i32;
29-
}
30-
let mut errno = 0;
31-
unsafe { suppress_iph!(_get_errno(&mut errno)) };
32-
let errno = errno_to_winerror(errno);
33-
io::Error::from_raw_os_error(errno)
27+
last_crt_error()
3428
} else {
3529
err
3630
}
3731
}
3832

33+
/// Get the last error from C runtime library functions (like _dup, _dup2, _fstat, etc.)
34+
/// CRT functions set errno, not GetLastError(), so we need to read errno directly.
35+
#[cfg(windows)]
36+
pub fn last_crt_error() -> io::Error {
37+
unsafe extern "C" {
38+
fn _get_errno(pValue: *mut i32) -> i32;
39+
}
40+
let mut errno = 0;
41+
unsafe { suppress_iph!(_get_errno(&mut errno)) };
42+
let winerror = errno_to_winerror(errno);
43+
io::Error::from_raw_os_error(winerror)
44+
}
45+
3946
#[cfg(not(windows))]
4047
pub fn last_os_error() -> io::Error {
4148
io::Error::last_os_error()

crates/vm/src/stdlib/nt.rs

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,13 @@ pub(crate) mod module {
2121
ospath::OsPath,
2222
stdlib::os::{_os, DirFd, FollowSymlinks, SupportFunc, TargetIsDirectory, errno_err},
2323
};
24+
25+
/// Convert the error stored in the C runtime `errno` variable into an Exception.
26+
/// Use this for CRT functions like _dup, _dup2, _fstat, etc. which set errno, not GetLastError().
27+
#[inline]
28+
fn crt_err(vm: &VirtualMachine) -> crate::builtins::PyBaseExceptionRef {
29+
crate::common::os::last_crt_error().to_pyexception(vm)
30+
}
2431
use libc::intptr_t;
2532
use std::os::windows::io::AsRawHandle;
2633
use std::{
@@ -876,7 +883,7 @@ pub(crate) mod module {
876883
fn dup(fd: i32, vm: &VirtualMachine) -> PyResult<i32> {
877884
let fd2 = unsafe { suppress_iph!(_dup(fd)) };
878885
if fd2 < 0 {
879-
return Err(errno_err(vm));
886+
return Err(crt_err(vm));
880887
}
881888
// Set the new fd as non-inheritable
882889
let borrowed = unsafe { crt_fd::Borrowed::borrow_raw(fd2) };
@@ -900,7 +907,7 @@ pub(crate) mod module {
900907
fn dup2(args: Dup2Args, vm: &VirtualMachine) -> PyResult<i32> {
901908
let result = unsafe { suppress_iph!(_dup2(args.fd, args.fd2)) };
902909
if result < 0 {
903-
return Err(errno_err(vm));
910+
return Err(crt_err(vm));
904911
}
905912
if !args.inheritable {
906913
let borrowed = unsafe { crt_fd::Borrowed::borrow_raw(args.fd2) };

0 commit comments

Comments
 (0)