Skip to content

Commit bebdf8e

Browse files
Add errno functions to c-api
1 parent e6e167f commit bebdf8e

3 files changed

Lines changed: 133 additions & 2 deletions

File tree

crates/capi/src/pyerrors.rs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ use crate::{PyObject, pystate::with_vm};
33
use core::convert::Infallible;
44
use core::ffi::{CStr, c_char, c_int};
55
use core::ptr::NonNull;
6-
use core::slice;
6+
pub use errno::*;
77
use rustpython_vm::builtins::{PyBaseException, PyTuple, PyType};
88
use rustpython_vm::convert::IntoObject;
99
use rustpython_vm::exceptions::ExceptionZoo;
@@ -14,6 +14,7 @@ pub use unicode::*;
1414
#[cfg(windows)]
1515
pub use windows::*;
1616

17+
mod errno;
1718
mod unicode;
1819
#[cfg(windows)]
1920
mod windows;
@@ -361,7 +362,7 @@ pub unsafe extern "C" fn PyErr_ExceptionMatches(exc: *mut PyObject) -> c_int {
361362

362363
#[unsafe(no_mangle)]
363364
pub extern "C" fn PyErr_BadArgument() -> c_int {
364-
with_vm::<PyResult<Infallible>, _>(|vm| {
365+
with_vm::<PyResult<Infallible>, ()>(|vm| {
365366
Err(vm.new_type_error("bad argument type for built-in operation"))
366367
});
367368
0

crates/capi/src/pyerrors/errno.rs

Lines changed: 117 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,117 @@
1+
use crate::unicodeobject::decode_fsdefault_and_size;
2+
use crate::{PyObject, pystate::with_vm};
3+
use core::convert::Infallible;
4+
use core::ffi::{CStr, c_char};
5+
use core::ptr::NonNull;
6+
use rustpython_vm::builtins::PyType;
7+
use rustpython_vm::convert::ToPyObject;
8+
use rustpython_vm::{AsObject, PyResult};
9+
10+
#[unsafe(no_mangle)]
11+
pub unsafe extern "C" fn PyErr_SetFromErrno(exc: *mut PyObject) -> *mut PyObject {
12+
unsafe {
13+
PyErr_SetFromErrnoWithFilenameObjects(exc, core::ptr::null_mut(), core::ptr::null_mut())
14+
}
15+
}
16+
17+
#[unsafe(no_mangle)]
18+
pub unsafe extern "C" fn PyErr_SetFromErrnoWithFilename(
19+
exc: *mut PyObject,
20+
filename: *const c_char,
21+
) -> *mut PyObject {
22+
with_vm::<PyResult<Infallible>, _>(|vm| {
23+
let errno = rustpython_vm::host_env::os::get_errno();
24+
let filename = if filename.is_null() {
25+
None
26+
} else {
27+
let filename_len = unsafe { CStr::from_ptr(filename) }.to_bytes().len();
28+
let filename = decode_fsdefault_and_size(vm, filename, filename_len)?;
29+
Some(filename.into())
30+
};
31+
32+
if errno == libc::EINTR {
33+
vm.check_signals()?;
34+
}
35+
36+
let exc_type = unsafe { &*exc }.try_downcast_ref::<PyType>(vm)?;
37+
let msg = if errno == 0 {
38+
vm.ctx.new_str("Error").into()
39+
} else {
40+
let msg = rustpython_vm::host_env::errno::strerror_string(errno)
41+
.unwrap_or_else(|| "Error".to_owned());
42+
vm.ctx.new_str(msg).into()
43+
};
44+
45+
let args = if let Some(filename) = filename {
46+
vec![errno.to_pyobject(vm), msg, filename]
47+
} else {
48+
vec![errno.to_pyobject(vm), msg]
49+
};
50+
let err = exc_type.as_object().call(args, vm)?;
51+
let err = err
52+
.downcast()
53+
.map_err(|_| vm.new_type_error("errno helper expected an exception instance"))?;
54+
Err(err)
55+
})
56+
}
57+
58+
#[unsafe(no_mangle)]
59+
pub unsafe extern "C" fn PyErr_SetFromErrnoWithFilenameObject(
60+
exc: *mut PyObject,
61+
filename: *mut PyObject,
62+
) -> *mut PyObject {
63+
unsafe { PyErr_SetFromErrnoWithFilenameObjects(exc, filename, core::ptr::null_mut()) }
64+
}
65+
66+
#[unsafe(no_mangle)]
67+
pub unsafe extern "C" fn PyErr_SetFromErrnoWithFilenameObjects(
68+
exc: *mut PyObject,
69+
filename: *mut PyObject,
70+
filename2: *mut PyObject,
71+
) -> *mut PyObject {
72+
with_vm::<PyResult<Infallible>, _>(|vm| {
73+
let errno = rustpython_vm::host_env::os::get_errno();
74+
if errno == libc::EINTR {
75+
vm.check_signals()?;
76+
}
77+
78+
let exc_type = unsafe { &*exc }.try_downcast_ref::<PyType>(vm)?;
79+
let msg = if errno == 0 {
80+
vm.ctx.new_str("Error").into()
81+
} else {
82+
let msg = rustpython_vm::host_env::errno::strerror_string(errno)
83+
.unwrap_or_else(|| "Error".to_owned());
84+
vm.ctx.new_str(msg).into()
85+
};
86+
87+
let filename = NonNull::new(filename).map_or_else(
88+
|| vm.ctx.none(),
89+
|filename| unsafe { filename.as_ref().to_owned() },
90+
);
91+
let filename2 = NonNull::new(filename2).map_or_else(
92+
|| vm.ctx.none(),
93+
|filename| unsafe { filename.as_ref().to_owned() },
94+
);
95+
96+
let args = if !vm.is_none(&filename2) {
97+
vec![
98+
errno.to_pyobject(vm),
99+
msg,
100+
filename,
101+
0.to_pyobject(vm),
102+
filename2,
103+
]
104+
} else if !vm.is_none(&filename) {
105+
vec![errno.to_pyobject(vm), msg, filename]
106+
} else {
107+
vec![errno.to_pyobject(vm), msg]
108+
};
109+
110+
let err = exc_type.as_object().call(args, vm)?;
111+
let err = err
112+
.downcast()
113+
.map_err(|_| vm.new_type_error("errno helper expected an exception instance"))?;
114+
115+
Err(err)
116+
})
117+
}

crates/capi/src/util.rs

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -205,6 +205,19 @@ impl FfiResult<()> for PyResult<Infallible> {
205205
}
206206
}
207207

208+
impl FfiResult<*mut PyObject> for PyResult<Infallible> {
209+
const ERR_VALUE: *mut PyObject = core::ptr::null_mut();
210+
211+
fn into_output(self, vm: &VirtualMachine) -> *mut PyObject {
212+
match self {
213+
Err(err) => {
214+
vm.set_exception(Some(err));
215+
Self::ERR_VALUE
216+
}
217+
}
218+
}
219+
}
220+
208221
impl<Output, T> FfiResult<Output> for PyResult<T>
209222
where
210223
T: FfiResult<Output>,

0 commit comments

Comments
 (0)