Skip to content

Commit 138c8a4

Browse files
committed
fix
1 parent f6db6ef commit 138c8a4

File tree

2 files changed

+91
-73
lines changed

2 files changed

+91
-73
lines changed

crates/vm/src/stdlib/ctypes.rs

Lines changed: 4 additions & 66 deletions
Original file line numberDiff line numberDiff line change
@@ -954,88 +954,26 @@ pub(crate) mod _ctypes {
954954
Ok(())
955955
}
956956

957-
std::thread_local! {
958-
/// Thread-local storage for ctypes errno
959-
/// This is separate from the system errno - ctypes swaps them during FFI calls
960-
/// when use_errno=True is specified.
961-
static CTYPES_LOCAL_ERRNO: std::cell::Cell<i32> = const { std::cell::Cell::new(0) };
962-
}
963-
964957
#[pyfunction]
965958
fn get_errno() -> i32 {
966-
CTYPES_LOCAL_ERRNO.with(|e| e.get())
959+
super::function::get_errno_value()
967960
}
968961

969962
#[pyfunction]
970963
fn set_errno(value: i32) -> i32 {
971-
CTYPES_LOCAL_ERRNO.with(|e| {
972-
let old = e.get();
973-
e.set(value);
974-
old
975-
})
976-
}
977-
978-
/// Save and restore errno around FFI call (called when use_errno=True)
979-
/// Before: restore thread-local errno to system
980-
/// After: save system errno to thread-local
981-
pub(super) fn save_and_restore_errno<F, R>(f: F) -> R
982-
where
983-
F: FnOnce() -> R,
984-
{
985-
// Before call: restore thread-local errno to system
986-
let saved = CTYPES_LOCAL_ERRNO.with(|e| e.get());
987-
errno::set_errno(errno::Errno(saved));
988-
989-
// Call the function
990-
let result = f();
991-
992-
// After call: save system errno to thread-local
993-
let new_error = errno::errno().0;
994-
CTYPES_LOCAL_ERRNO.with(|e| e.set(new_error));
995-
996-
result
997-
}
998-
999-
#[cfg(windows)]
1000-
std::thread_local! {
1001-
/// Thread-local storage for ctypes last_error
1002-
static CTYPES_LOCAL_LAST_ERROR: std::cell::Cell<u32> = const { std::cell::Cell::new(0) };
964+
super::function::set_errno_value(value)
1003965
}
1004966

1005967
#[cfg(windows)]
1006968
#[pyfunction]
1007969
fn get_last_error() -> PyResult<u32> {
1008-
Ok(CTYPES_LOCAL_LAST_ERROR.with(|e| e.get()))
970+
Ok(super::function::get_last_error_value())
1009971
}
1010972

1011973
#[cfg(windows)]
1012974
#[pyfunction]
1013975
fn set_last_error(value: u32) -> u32 {
1014-
CTYPES_LOCAL_LAST_ERROR.with(|e| {
1015-
let old = e.get();
1016-
e.set(value);
1017-
old
1018-
})
1019-
}
1020-
1021-
/// Save and restore last_error around FFI call (called when use_last_error=True)
1022-
#[cfg(windows)]
1023-
pub(super) fn save_and_restore_last_error<F, R>(f: F) -> R
1024-
where
1025-
F: FnOnce() -> R,
1026-
{
1027-
// Before call: restore thread-local last_error to Windows
1028-
let saved = CTYPES_LOCAL_LAST_ERROR.with(|e| e.get());
1029-
unsafe { windows_sys::Win32::Foundation::SetLastError(saved) };
1030-
1031-
// Call the function
1032-
let result = f();
1033-
1034-
// After call: save Windows last_error to thread-local
1035-
let new_error = unsafe { windows_sys::Win32::Foundation::GetLastError() };
1036-
CTYPES_LOCAL_LAST_ERROR.with(|e| e.set(new_error));
1037-
1038-
result
976+
super::function::set_last_error_value(value)
1039977
}
1040978

1041979
#[pyattr]

crates/vm/src/stdlib/ctypes/function.rs

Lines changed: 87 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,90 @@ pub(super) const INTERNAL_CAST_ADDR: usize = 1;
3232
pub(super) const INTERNAL_STRING_AT_ADDR: usize = 2;
3333
pub(super) const INTERNAL_WSTRING_AT_ADDR: usize = 3;
3434

35+
// Thread-local errno storage for ctypes
36+
std::thread_local! {
37+
/// Thread-local storage for ctypes errno
38+
/// This is separate from the system errno - ctypes swaps them during FFI calls
39+
/// when use_errno=True is specified.
40+
static CTYPES_LOCAL_ERRNO: std::cell::Cell<i32> = const { std::cell::Cell::new(0) };
41+
}
42+
43+
/// Get ctypes thread-local errno value
44+
pub(super) fn get_errno_value() -> i32 {
45+
CTYPES_LOCAL_ERRNO.with(|e| e.get())
46+
}
47+
48+
/// Set ctypes thread-local errno value, returns old value
49+
pub(super) fn set_errno_value(value: i32) -> i32 {
50+
CTYPES_LOCAL_ERRNO.with(|e| {
51+
let old = e.get();
52+
e.set(value);
53+
old
54+
})
55+
}
56+
57+
/// Save and restore errno around FFI call (called when use_errno=True)
58+
/// Before: restore thread-local errno to system
59+
/// After: save system errno to thread-local
60+
#[cfg(not(windows))]
61+
fn save_and_restore_errno<F, R>(f: F) -> R
62+
where
63+
F: FnOnce() -> R,
64+
{
65+
// Before call: restore thread-local errno to system
66+
let saved = CTYPES_LOCAL_ERRNO.with(|e| e.get());
67+
errno::set_errno(errno::Errno(saved));
68+
69+
// Call the function
70+
let result = f();
71+
72+
// After call: save system errno to thread-local
73+
let new_error = errno::errno().0;
74+
CTYPES_LOCAL_ERRNO.with(|e| e.set(new_error));
75+
76+
result
77+
}
78+
79+
#[cfg(windows)]
80+
std::thread_local! {
81+
/// Thread-local storage for ctypes last_error (Windows only)
82+
static CTYPES_LOCAL_LAST_ERROR: std::cell::Cell<u32> = const { std::cell::Cell::new(0) };
83+
}
84+
85+
#[cfg(windows)]
86+
pub(super) fn get_last_error_value() -> u32 {
87+
CTYPES_LOCAL_LAST_ERROR.with(|e| e.get())
88+
}
89+
90+
#[cfg(windows)]
91+
pub(super) fn set_last_error_value(value: u32) -> u32 {
92+
CTYPES_LOCAL_LAST_ERROR.with(|e| {
93+
let old = e.get();
94+
e.set(value);
95+
old
96+
})
97+
}
98+
99+
/// Save and restore last_error around FFI call (called when use_last_error=True)
100+
#[cfg(windows)]
101+
fn save_and_restore_last_error<F, R>(f: F) -> R
102+
where
103+
F: FnOnce() -> R,
104+
{
105+
// Before call: restore thread-local last_error to Windows
106+
let saved = CTYPES_LOCAL_LAST_ERROR.with(|e| e.get());
107+
unsafe { windows_sys::Win32::Foundation::SetLastError(saved) };
108+
109+
// Call the function
110+
let result = f();
111+
112+
// After call: save Windows last_error to thread-local
113+
let new_error = unsafe { windows_sys::Win32::Foundation::GetLastError() };
114+
CTYPES_LOCAL_LAST_ERROR.with(|e| e.set(new_error));
115+
116+
result
117+
}
118+
35119
type FP = unsafe extern "C" fn();
36120

37121
/// Get FFI type for a ctypes type code
@@ -1624,23 +1708,19 @@ impl Callable for PyCFuncPtr {
16241708
// 7. Get flags to check for use_last_error
16251709
let flags = PyCFuncPtr::_flags_(zelf, vm);
16261710

1627-
// 8. Call the function (with use_last_error handling on Windows)
1711+
// 8. Call the function (with use_last_error/use_errno handling)
16281712
#[cfg(windows)]
16291713
let raw_result = {
16301714
if flags & super::base::StgInfoFlags::FUNCFLAG_USE_LASTERROR.bits() != 0 {
1631-
super::_ctypes::save_and_restore_last_error(|| {
1632-
ctypes_callproc(code_ptr, &arguments, &call_info)
1633-
})
1715+
save_and_restore_last_error(|| ctypes_callproc(code_ptr, &arguments, &call_info))
16341716
} else {
16351717
ctypes_callproc(code_ptr, &arguments, &call_info)
16361718
}
16371719
};
16381720
#[cfg(not(windows))]
16391721
let raw_result = {
16401722
if flags & super::base::StgInfoFlags::FUNCFLAG_USE_ERRNO.bits() != 0 {
1641-
super::_ctypes::save_and_restore_errno(|| {
1642-
ctypes_callproc(code_ptr, &arguments, &call_info)
1643-
})
1723+
save_and_restore_errno(|| ctypes_callproc(code_ptr, &arguments, &call_info))
16441724
} else {
16451725
ctypes_callproc(code_ptr, &arguments, &call_info)
16461726
}

0 commit comments

Comments
 (0)