Skip to content

Navigation Menu

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Commit f0141b9

Browse filesBrowse files
committed
initial updates
Signed-off-by: Ashwin Naren <arihant2math@gmail.com>
1 parent 510b9db commit f0141b9
Copy full SHA for f0141b9

File tree

3 files changed

+201
-9
lines changed
Filter options

3 files changed

+201
-9
lines changed

‎extra_tests/snippets/builtins_ctypes.py

Copy file name to clipboardExpand all lines: extra_tests/snippets/builtins_ctypes.py
+132Lines changed: 132 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,29 @@
11
import os as _os, sys as _sys
2+
import types as _types
23

4+
from _ctypes import RTLD_LOCAL, RTLD_GLOBAL
35
from _ctypes import sizeof
46
from _ctypes import _SimpleCData
7+
from _ctypes import CFuncPtr as _CFuncPtr
8+
59
from struct import calcsize as _calcsize
610

11+
12+
DEFAULT_MODE = RTLD_LOCAL
13+
if _os.name == "posix" and _sys.platform == "darwin":
14+
# On OS X 10.3, we use RTLD_GLOBAL as default mode
15+
# because RTLD_LOCAL does not work at least on some
16+
# libraries. OS X 10.3 is Darwin 7, so we check for
17+
# that.
18+
19+
if int(_os.uname().release.split('.')[0]) < 8:
20+
DEFAULT_MODE = RTLD_GLOBAL
21+
22+
from _ctypes import FUNCFLAG_CDECL as _FUNCFLAG_CDECL, \
23+
FUNCFLAG_PYTHONAPI as _FUNCFLAG_PYTHONAPI, \
24+
FUNCFLAG_USE_ERRNO as _FUNCFLAG_USE_ERRNO, \
25+
FUNCFLAG_USE_LASTERROR as _FUNCFLAG_USE_LASTERROR
26+
727
def create_string_buffer(init, size=None):
828
"""create_string_buffer(aBytes) -> character array
929
create_string_buffer(anInteger) -> character array
@@ -131,3 +151,115 @@ class c_bool(_SimpleCData):
131151
# s = create_string_buffer(b'\000' * 32)
132152
assert i.value == 42
133153
assert f.value == 3.14
154+
155+
if _os.name == "nt":
156+
from _ctypes import LoadLibrary as _dlopen
157+
from _ctypes import FUNCFLAG_STDCALL as _FUNCFLAG_STDCALL
158+
159+
class CDLL(object):
160+
"""An instance of this class represents a loaded dll/shared
161+
library, exporting functions using the standard C calling
162+
convention (named 'cdecl' on Windows).
163+
164+
The exported functions can be accessed as attributes, or by
165+
indexing with the function name. Examples:
166+
167+
<obj>.qsort -> callable object
168+
<obj>['qsort'] -> callable object
169+
170+
Calling the functions releases the Python GIL during the call and
171+
reacquires it afterwards.
172+
"""
173+
_func_flags_ = _FUNCFLAG_CDECL
174+
_func_restype_ = c_int
175+
# default values for repr
176+
_name = '<uninitialized>'
177+
_handle = 0
178+
_FuncPtr = None
179+
180+
def __init__(self, name, mode=DEFAULT_MODE, handle=None,
181+
use_errno=False,
182+
use_last_error=False,
183+
winmode=None):
184+
self._name = name
185+
flags = self._func_flags_
186+
if use_errno:
187+
flags |= _FUNCFLAG_USE_ERRNO
188+
if use_last_error:
189+
flags |= _FUNCFLAG_USE_LASTERROR
190+
if _sys.platform.startswith("aix"):
191+
"""When the name contains ".a(" and ends with ")",
192+
e.g., "libFOO.a(libFOO.so)" - this is taken to be an
193+
archive(member) syntax for dlopen(), and the mode is adjusted.
194+
Otherwise, name is presented to dlopen() as a file argument.
195+
"""
196+
if name and name.endswith(")") and ".a(" in name:
197+
mode |= ( _os.RTLD_MEMBER | _os.RTLD_NOW )
198+
if _os.name == "nt":
199+
if winmode is not None:
200+
mode = winmode
201+
else:
202+
import nt
203+
mode = 4096
204+
if '/' in name or '\\' in name:
205+
self._name = nt._getfullpathname(self._name)
206+
mode |= nt._LOAD_LIBRARY_SEARCH_DLL_LOAD_DIR
207+
208+
class _FuncPtr(_CFuncPtr):
209+
_flags_ = flags
210+
_restype_ = self._func_restype_
211+
self._FuncPtr = _FuncPtr
212+
213+
if handle is None:
214+
self._handle = _dlopen(self._name, mode)
215+
else:
216+
self._handle = handle
217+
218+
def __repr__(self):
219+
return "<%s '%s', handle %x at %#x>" % \
220+
(self.__class__.__name__, self._name,
221+
(self._handle & (_sys.maxsize*2 + 1)),
222+
id(self) & (_sys.maxsize*2 + 1))
223+
224+
def __getattr__(self, name):
225+
if name.startswith('__') and name.endswith('__'):
226+
raise AttributeError(name)
227+
func = self.__getitem__(name)
228+
setattr(self, name, func)
229+
return func
230+
231+
def __getitem__(self, name_or_ordinal):
232+
func = self._FuncPtr((name_or_ordinal, self))
233+
if not isinstance(name_or_ordinal, int):
234+
func.__name__ = name_or_ordinal
235+
return func
236+
237+
class LibraryLoader(object):
238+
def __init__(self, dlltype):
239+
self._dlltype = dlltype
240+
241+
def __getattr__(self, name):
242+
if name[0] == '_':
243+
raise AttributeError(name)
244+
try:
245+
dll = self._dlltype(name)
246+
except OSError:
247+
raise AttributeError(name)
248+
setattr(self, name, dll)
249+
return dll
250+
251+
def __getitem__(self, name):
252+
return getattr(self, name)
253+
254+
def LoadLibrary(self, name):
255+
return self._dlltype(name)
256+
257+
__class_getitem__ = classmethod(_types.GenericAlias)
258+
259+
cdll = LibraryLoader(CDLL)
260+
261+
if _os.name == "posix" and _sys.platform == "darwin":
262+
pass
263+
else:
264+
libc = cdll.msvcrt
265+
print(libc.rand())

‎vm/src/stdlib/ctypes.rs

Copy file name to clipboardExpand all lines: vm/src/stdlib/ctypes.rs
+2-2Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ pub(crate) mod _ctypes {
3737
use super::base::PyCSimple;
3838
use crate::builtins::PyTypeRef;
3939
use crate::class::StaticType;
40-
use crate::function::Either;
40+
use crate::function::{Either, OptionalArg};
4141
use crate::stdlib::ctypes::library;
4242
use crate::{AsObject, PyObjectRef, PyResult, TryFromObject, VirtualMachine};
4343
use crossbeam_utils::atomic::AtomicCell;
@@ -171,7 +171,7 @@ pub(crate) mod _ctypes {
171171
}
172172

173173
#[pyfunction(name = "LoadLibrary")]
174-
fn load_library(name: String, vm: &VirtualMachine) -> PyResult<usize> {
174+
fn load_library(name: String, load_flags: OptionalArg<i32>, vm: &VirtualMachine) -> PyResult<usize> {
175175
// TODO: audit functions first
176176
let cache = library::libcache();
177177
let mut cache_write = cache.write();

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

Copy file name to clipboard
+67-7Lines changed: 67 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,60 @@
11
use crate::stdlib::ctypes::PyCData;
2-
use crate::PyObjectRef;
2+
use crate::{Py, PyObjectRef, PyResult, VirtualMachine};
33
use crossbeam_utils::atomic::AtomicCell;
4-
use rustpython_common::lock::PyRwLock;
4+
use rustpython_common::lock::{PyMutex, PyRwLock};
55
use std::ffi::c_void;
6+
use std::fmt::Debug;
7+
use std::sync::Arc;
8+
use crate::types::Callable;
9+
10+
#[derive(Debug)]
11+
pub enum FunctionArgument {
12+
Float(std::ffi::c_float),
13+
Double(std::ffi::c_double),
14+
// TODO: Duplicate char stuff
15+
UChar(std::ffi::c_uchar),
16+
SChar(std::ffi::c_schar),
17+
Char(std::ffi::c_char),
18+
UShort(std::ffi::c_ushort),
19+
Short(std::ffi::c_short),
20+
UInt(std::ffi::c_uint),
21+
Int(std::ffi::c_int),
22+
ULong(std::ffi::c_ulong),
23+
Long(std::ffi::c_long),
24+
ULongLong(std::ffi::c_ulonglong),
25+
LongLong(std::ffi::c_longlong),
26+
}
627

728
#[derive(Debug)]
829
pub struct Function {
9-
_pointer: *mut c_void,
10-
_arguments: Vec<()>,
11-
_return_type: Box<()>,
30+
// TODO: no protection from use-after-free
31+
pointer: Arc<PyMutex<*mut c_void>>,
32+
arguments: Vec<FunctionArgument>,
33+
}
34+
35+
unsafe impl Send for Function {}
36+
unsafe impl Sync for Function {}
37+
38+
impl Function {
39+
pub unsafe fn load(library: &libloading::Library, function: &str, args: Vec<PyObjectRef>, return_type: PyObjectRef) -> PyResult<Self> {
40+
let pointer = library.get(function + b'\0').map_err(|err| err.to_string()).unwrap();
41+
library.
42+
Ok(Function {
43+
pointer: Arc::new(PyMutex::new(*pointer)),
44+
arguments: args.iter().map(|arg| {
45+
todo!("convert PyObjectRef to FunctionArgument")
46+
}).collect(),
47+
})
48+
}
49+
50+
pub unsafe fn call(&self, args: Vec<PyObjectRef>) -> PyObjectRef {
51+
// assemble function type signature
52+
53+
}
1254
}
1355

1456
#[pyclass(module = "_ctypes", name = "CFuncPtr", base = "PyCData")]
57+
#[derive(PyPayload)]
1558
pub struct PyCFuncPtr {
1659
pub _name_: String,
1760
pub _argtypes_: AtomicCell<Vec<PyObjectRef>>,
@@ -20,5 +63,22 @@ pub struct PyCFuncPtr {
2063
_f: PyRwLock<Function>,
2164
}
2265

23-
#[pyclass]
24-
impl PyCFuncPtr {}
66+
impl Debug for PyCFuncPtr {
67+
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
68+
f.debug_struct("PyCFuncPtr")
69+
.field("_name_", &self._name_)
70+
.finish()
71+
}
72+
}
73+
74+
impl Callable for PyCFuncPtr {
75+
type Args = Vec<PyObjectRef>;
76+
77+
fn call(zelf: &Py<Self>, _args: Self::Args, vm: &VirtualMachine) -> PyResult {
78+
todo!()
79+
}
80+
}
81+
82+
#[pyclass(flags(BASETYPE), with(Callable))]
83+
impl PyCFuncPtr {
84+
}

0 commit comments

Comments
0 (0)
Morty Proxy This is a proxified and sanitized view of the page, visit original site.