mirror of
https://github.com/RustPython/RustPython.git
synced 2026-10-28 18:59:04 +08:00
Preserve callable addresses in ctypes function pointer casts (#8965)
Read the stored executable address when casting a function pointer and accept function pointer types as cast destinations. The existing ownership dictionary retains the original callback through a cast roundtrip. Extracted independently on the unchanged Python 3.14 target, without typed callback argument or broader py_object transport changes. One unique callback-address/ownership regression extends the existing ctypes snippet; canonical coverage was checked for duplicates. Assisted-by: Codex:model-version-unavailable
This commit is contained in:
1 parent
e5f332fda4
commit
f46ba48f10
2 files changed
+18
-1
No files matched your search
@@ -509,7 +509,10 @@ fn cast_check_pointertype(ctype: &PyObject, vm: &VirtualMachine) -> bool {
|
||||
return true;
|
||||
}
|
||||
|
||||
// PyCFuncPtrTypeObject_Check - TODO
|
||||
// PyCFuncPtrTypeObject_Check
|
||||
if ctype.class().fast_issubclass(PyCFuncPtrType::static_type()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// simple pointer types via StgInfo.proto (c_void_p, c_char_p, etc.)
|
||||
if let Ok(type_attr) = ctype.get_attr("_type_", vm)
|
||||
@@ -562,6 +565,9 @@ pub(super) fn cast_impl(
|
||||
// Simple type (c_void_p, c_char_p, etc.) → value from buffer
|
||||
let buffer = simple.0.buffer.read();
|
||||
rustpython_host_env::ctypes::read_pointer_from_buffer(&buffer)
|
||||
} else if let Some(funcptr) = obj.downcast_ref::<PyCFuncPtr>() {
|
||||
// A function pointer stores the executable address in its buffer.
|
||||
funcptr.get_func_ptr()
|
||||
} else if let Some(cdata) = obj.downcast_ref::<PyCData>() {
|
||||
// Array, Structure, Union → buffer address (b_ptr)
|
||||
cdata.buffer.read().as_ptr() as usize
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import ctypes
|
||||
import gc
|
||||
import itertools
|
||||
import os as _os
|
||||
import sys as _sys
|
||||
@@ -458,4 +459,14 @@ except MemoryError:
|
||||
else:
|
||||
raise AssertionError("an unallocatable array was created")
|
||||
|
||||
# A function-pointer cast retains the callback and its executable address.
|
||||
Unary = ctypes.CFUNCTYPE(ctypes.c_int, ctypes.c_int)
|
||||
callback = Unary(lambda value: value + 1)
|
||||
address = ctypes.cast(callback, ctypes.c_void_p)
|
||||
roundtrip = ctypes.cast(address, Unary)
|
||||
assert roundtrip._objects[id(callback)] is callback
|
||||
del callback, address
|
||||
gc.collect()
|
||||
assert roundtrip(41) == 42
|
||||
|
||||
print("done")
|
||||
Reference in new issue
Block a user