10000 error handling · RustPython/RustPython@aeba7ad · GitHub
[go: up one dir, main page]

Skip to content

Commit aeba7ad

Browse files
committed
error handling
Signed-off-by: Ashwin Naren <arihant2math@gmail.com>
1 parent afd1f64 commit aeba7ad

File tree

2 files changed

+106
-36
lines changed

2 files changed

+106
-36
lines changed

vm/src/stdlib/ctypes/base.rs

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,31 @@ use num_traits::ToPrimitive;
1010
use rustpython_common::lock::PyRwLock;
1111
use std::fmt::Debug;
1212

13+
pub fn ffi_type_from_str(_type_: &str) -> Option<libffi::middle::Type> {
14+
match _type_ {
15+
"c" => Some(libffi::middle::Type::u8()),
16+
"u" => Some(libffi::middle::Type::u32()),
17+
"b" => Some(libffi::middle::Type::i8()),
18+
"B" => Some(libffi::middle::Type::u8()),
19+
"h" => Some(libffi::middle::Type::< 8000 /span>i16()),
20+
"H" => Some(libffi::middle::Type::u16()),
21+
"i" => Some(libffi::middle::Type::i32()),
22+
"I" => Some(libffi::middle::Type::u32()),
23+
"l" => Some(libffi::middle::Type::i32()),
24+
"L" => Some(libffi::middle::Type::u32()),
25+
"q" => Some(libffi::middle::Type::i64()),
26+
"Q" => Some(libffi::middle::Type::u64()),
27+
"f" => Some(libffi::middle::Type::f32()),
28+
"d" => Some(libffi::middle::Type::f64()),
29+
"g" => Some(libffi::middle::Type::f64()),
30+
"?" => Some(libffi::middle::Type::u8()),
31+
"z" => Some(libffi::middle::Type::u64()),
32+
"Z" => Some(libffi::middle::Type::u64()),
33+
"P" => Some(libffi::middle::Type::u64()),
34+
_ => None,
35+
}
36+
}
37+
1338
#[allow(dead_code)]
1439
fn set_primitive(_type_: &str, value: &PyObjectRef, vm: &VirtualMachine) -> PyResult {
1540
match _type_ {

vm/src/stdlib/ctypes/function.rs

Lines changed: 81 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -1,31 +1,31 @@
11
use crate::builtins::{PyStr, PyTuple, PyTypeRef};
2+
use crate::class::StaticType;
3+
use crate::convert::ToPyObject;
4+
use crate::function::FuncArgs;
25
use crate::stdlib::ctypes::PyCData;
6+
use crate::stdlib::ctypes::base::{PyCSimple, ffi_type_from_str};
37
use crate::types::{Callable, Constructor};
48
use crate::{AsObject, Py, PyObjectRef, PyResult, VirtualMachine};
59
use crossbeam_utils::atomic::AtomicCell;
6-
use std::fmt::Debug;
7-
use crate::class::StaticType;
8-
use crate::stdlib::ctypes::base::PyCSimple;
910
use libffi::middle::{Arg, Cif, CodePtr, Type};
1011
use libloading::Symbol;
1112
use num_traits::ToPrimitive;
1213
use rustpython_common::lock::PyRwLock;
13-
use crate::convert::ToPyObject;
14-
use crate::function::FuncArgs;
15-
// https://github.com/python/cpython/blob/4f8bb3947cfbc20f970ff9d9531e1132a9e95396/Modules/_ctypes/callproc.c#L15
14+
use std::fmt::Debug;
1615

16+
// https://github.com/python/cpython/blob/4f8bb3947cfbc20f970ff9d9531e1132a9e95396/Modules/_ctypes/callproc.c#L15
1717

1818
#[derive(Debug)]
1919
pub struct Function {
2020
// TODO: no protection from use-after-free
2121
pointer: CodePtr,
22-
cif: Cif
22+
cif: Cif,
2323
}
2424

2525
unsafe impl Send for Function {}
2626
unsafe impl Sync for Function {}
2727

28-
type FP = unsafe extern "C" fn ();
28+
type FP = unsafe extern "C" fn();
2929

3030
impl Function {
3131
pub unsafe fn load(
@@ -36,25 +36,29 @@ impl Function {
3636
vm: &VirtualMachine,
3737
) -> PyResult<Self> {
3838
// map each arg to a PyCSimple
39-
let args = args.into_iter().map(|arg| {
40-
if arg.is_subclass(PyCSimple::static_type().as_object(), vm).unwrap() {
41-
let arg_type = arg.get_attr("_type_", vm).unwrap().str(vm).unwrap().to_string();
42-
let _value = arg.get_attr("value", vm).unwrap();
43-
match &*arg_type {
44-
_ => todo!("HANDLE ARG TYPE")
39+
let args = args
40+
.into_iter()
41+
.map(|arg| {
42+
if let Some(data) = arg.downcast_ref::<PyCSimple>() {
43+
Ok(ffi_type_from_str(&data._type_).unwrap())
44+
} else {
45+
Err(vm.new_type_error("Expected a ctypes simple type".to_string()))
4546
}
46-
} else {
47-
todo!("HANDLE ERROR")
48-
}
49-
}).collect::<Vec<Type>>();
47+
})
48+
.collect::<PyResult<Vec<Type>>>()?;
5049
let terminated = format!("{}\0", function);
51-
let pointer: Symbol<FP> = unsafe { library
52-
.get(terminated.as_bytes())
53-
.map_err(|err| err.to_string())
54-
.unwrap() };
50+
let pointer: Symbol<FP> = unsafe {
51+
library
52+
.get(terminated.as_bytes())
53+
.map_err(|err| err.to_string())
54+
.map_err(|err| vm.new_value_error(err))?
55+
};
5556
let code_ptr = CodePtr(*pointer as *mut _);
5657
let return_type = match ret_type {
57-
Some(_t) => todo!("HANDLE RETURN TYPE"),
58+
// TODO: Fix this
59+
Some(_t) => {
60+
return Err(vm.new_not_implemented_error("Return type not implemented".to_string()));
61+
}
5862
None => Type::c_int(),
5963
};
6064
let cif = Cif::new(args.into_iter(), return_type);
@@ -64,11 +68,25 @@ impl Function {
6468
})
6569
}
6670

67-
pub unsafe fn call(&self, _args: Vec<PyObjectRef>, vm: &VirtualMachine) -> PyObjectRef {
68-
let args: Vec<Arg> = vec![];
71+
pub unsafe fn call(
72+
&self,
73+
args: Vec<PyObjectRef>,
74+
vm: &VirtualMachine,
75+
) -> PyResult<PyObjectRef> {
76+
let args = args
77+
.into_iter()
78+
.map(|arg| {
79+
if let Some(data) = arg.downcast_ref::<PyCSimple>() {
80+
dbg!(&data);
81+
todo!("HANDLE ARGUMENTS")
82+
} else {
83+
Err(vm.new_type_error("Expected a ctypes simple type".to_string()))
84+
}
85+
})
86+
.collect::<PyResult<Vec<Arg>>>()?;
6987
// TODO: FIX return type
7088
let result: i32 = unsafe { self.cif.call(self.pointer, &args) };
71-
vm.ctx.new_int(result).into()
89+
Ok(vm.ctx.new_int(result).into())
7290
}
7391
}
7492

@@ -80,7 +98,7 @@ pub struct PyCFuncPtr {
8098
// FIXME(arihant2math): This shouldn't be an option, setting the default as the none type should work
8199
// This is a workaround for now and I'll fix it later
82100
pub _restype_: PyRwLock<Option<PyTypeRef>>,
83-
pub handler: PyObjectRef
101+
pub handler: PyObjectRef,
84102
}
85103

86104
impl Debug for PyCFuncPtr {
@@ -95,16 +113,31 @@ impl Constructor for PyCFuncPtr {
95113
type Args = FuncArgs;
96114

97115
fn py_new(_cls: PyTypeRef, args: Self::Args, vm: &VirtualMachine) -> PyResult {
98-
let tuple = args.args.first().unwrap();
99-
let tuple: &Py<PyTuple> = tuple.downcast_ref().unwrap();
100-
let name = tuple.first().unwrap().downcast_ref::<PyStr>().unwrap().to_string();
101-
let handler = tuple.into_iter().nth(1).unwrap().clone();
116+
let tuple = args.args.first().ok_or_else(|| {
117+
vm.new_type_error("CFuncPtr() takes exactly 1 argument (0 given)".to_string())
118+
})?;
119+
let tuple: &Py<PyTuple> = tuple
120+
.downcast_ref()
121+
.ok_or(vm.new_type_error("Expected a tuple".to_string()))?;
122+
let name = tuple
123+
.first()
124+
.ok_or(vm.new_type_error("Expected a tuple with at least 2 elements".to_string()))?
125+
.downcast_ref::<PyStr>()
126+
.ok_or(vm.new_type_error("Expected a string".to_string()))?
127+
.to_string();
128+
let handler = tuple
129+
.into_iter()
130+
.nth(1)
131+
.ok_or(vm.new_type_error("Expected a tuple with at least 2 elements".to_string()))?
132+
.to_object()
133+
.clone();
102134
Ok(Self {
103135
_flags_: AtomicCell::new(0),
104136
name: PyRwLock::new(name),
105137
_restype_: PyRwLock::new(None),
106-
handler
107-
}.to_pyobject(vm))
138+
handler,
139+
}
140+
.to_pyobject(vm))
108141
}
109142
}
110143

@@ -115,12 +148,24 @@ impl Callable for PyCFuncPtr {
115148
let handle = zelf.handler.get_attr("_handle", vm)?;
116149
let handle = handle.try_int(vm)?.as_bigint().clone();
117150
let library_cache = crate::stdlib::ctypes::library::libcache().read();
118-
let library = library_cache.get_lib(handle.to_usize().unwrap()).unwrap();
151+
let library = library_cache
152+
.get_lib(
153+
handle
154+
.to_usize()
155+
.ok_or(vm.new_value_error("Invalid handle".to_string()))?,
156+
)
157+
.ok_or_else(|| vm.new_value_error("Library not found".to_string()))?;
119158
let inner_lib = library.lib.lock();
120159
let name = zelf.name.read();
121160
let res_type = zelf._restype_.read();
122-
let func = Function::load(inner_lib.as_ref().unwrap(), &name, &args.args, &res_type, vm)?;
123-
Ok(func.call(args.args, vm))
161+
let func = Function::load(
162+
inner_lib.as_ref().unwrap(),
163+
&name,
164+
&args.args,
165+
&res_type,
166+
vm,
167+
)?;
168+
Ok(func.call(args.args, vm)?)
124169
}
125170
}
126171
}

0 commit comments

Comments
 (0)
0