Skip to content

Commit 4c8b267

Browse files
committed
last crt error
1 parent cc534d2 commit 4c8b267

File tree

4 files changed

+34
-15
lines changed

4 files changed

+34
-15
lines changed

Lib/test/test_os.py

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2429,12 +2429,10 @@ def test_ftruncate(self):
24292429
self.check(os.ftruncate, 0)
24302430
self.check_bool(os.truncate, 0)
24312431

2432-
@unittest.expectedFailureIfWindows('TODO: RUSTPYTHON; (OSError: [Errno 18] There are no more files.)')
24332432
@unittest.skipUnless(hasattr(os, 'lseek'), 'test needs os.lseek()')
24342433
def test_lseek(self):
24352434
self.check(os.lseek, 0, 0)
24362435

2437-
@unittest.expectedFailureIfWindows('TODO: RUSTPYTHON; (OSError: [Errno 18] There are no more files.)')
24382436
@unittest.skipUnless(hasattr(os, 'read'), 'test needs os.read()')
24392437
def test_read(self):
24402438
self.check(os.read, 1)
@@ -2448,7 +2446,6 @@ def test_readv(self):
24482446
def test_tcsetpgrpt(self):
24492447
self.check(os.tcsetpgrp, 0)
24502448

2451-
@unittest.expectedFailureIfWindows('TODO: RUSTPYTHON; (OSError: [Errno 18] There are no more files.)')
24522449
@unittest.skipUnless(hasattr(os, 'write'), 'test needs os.write()')
24532450
def test_write(self):
24542451
self.check(os.write, b" ")
@@ -2457,7 +2454,6 @@ def test_write(self):
24572454
def test_writev(self):
24582455
self.check(os.writev, [b'abc'])
24592456

2460-
@unittest.expectedFailureIfWindows('TODO: RUSTPYTHON; os.get_inheritable not implemented yet for all platforms')
24612457
@support.requires_subprocess()
24622458
def test_inheritable(self):
24632459
self.check(os.get_inheritable)

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::{env, fs, io, mem::MaybeUninit, os::windows::ffi::OsStringExt};
@@ -777,7 +784,7 @@ pub(crate) mod module {
777784
fn dup(fd: i32, vm: &VirtualMachine) -> PyResult<i32> {
778785
let fd2 = unsafe { suppress_iph!(_dup(fd)) };
779786
if fd2 < 0 {
780-
return Err(errno_err(vm));
787+
return Err(crt_err(vm));
781788
}
782789
let borrowed = unsafe { crt_fd::Borrowed::borrow_raw(fd2) };
783790
let handle = crt_fd::as_handle(borrowed).map_err(|e| close_fd_and_raise(fd2, e, vm))?;
@@ -800,7 +807,7 @@ pub(crate) mod module {
800807
fn dup2(args: Dup2Args, vm: &VirtualMachine) -> PyResult<i32> {
801808
let result = unsafe { suppress_iph!(_dup2(args.fd, args.fd2)) };
802809
if result < 0 {
803-
return Err(errno_err(vm));
810+
return Err(crt_err(vm));
804811
}
805812
if !args.inheritable {
806813
let borrowed = unsafe { crt_fd::Borrowed::borrow_raw(args.fd2) };

0 commit comments

Comments
 (0)