⚡ Sangsakala Proxy 🏠 Home
Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
Fix ctypes field byte order and encoded instance copies
Assisted-by: Codex:GPT-6
  • Loading branch information
1ndahous3 committed Oct 19, 2026
commit f23e581c9d1a3c9fc4b7f18b8202ccd2791fd7e7
25 changes: 16 additions & 9 deletions crates/vm/src/stdlib/_ctypes/base.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1073,6 +1073,20 @@ impl PyCData {
}
}

// A compatible ctypes instance already contains the encoded field bytes.
// Snapshot them before writing: source and destination may share storage.
if let Some(proto_type) = proto.downcast_ref::<PyType>()
&& value.class().fast_issubclass(proto_type)
&& let Some(source) = value.downcast_ref::<Self>()
Comment thread
1ndahous3 marked this conversation as resolved.
Resolved
{
let bytes = {
let buffer = source.buffer.read();
rustpython_host_env::ctypes::copy_to_sized_bytes(&buffer, size)
};
self.write_bytes_at_offset(offset, &bytes);
return self.keep_cdata(index, &value, vm);
}

// Special handling for Pointer fields with Array values
if let Some(proto_type) = proto.downcast_ref::<PyType>()
&& proto_type
Expand Down Expand Up @@ -1260,10 +1274,7 @@ impl PyCData {
.as_object()
.get_attr("_swappedbytes_", vm)
.is_ok()
|| proto_type
.as_object()
.get_attr("_swappedbytes_", vm)
.is_ok();
|| super::simple::is_swapped(&proto_type);

let data = if needs_swap && size > 1 {
let mut swapped = buffer_data;
Expand Down Expand Up @@ -1916,11 +1927,7 @@ impl Py<PyCField> {
.as_object()
.get_attr("_swappedbytes_", vm)
.is_ok()
|| zelf
.proto
.as_object()
.get_attr("_swappedbytes_", vm)
.is_ok())
|| super::simple::is_swapped(&zelf.proto))
&& size > 1;

// PyCData_set
Expand Down
16 changes: 16 additions & 0 deletions extra_tests/snippets/stdlib_ctypes.py
Original file line number Diff line number Diff line change
Expand Up @@ -795,3 +795,19 @@ class IndexedSwapped(_swapped):
_words = (IndexedSwapped * 1).from_buffer_copy(b"\x01\x02\x03\x04")
assert type(_words[0]) is IndexedSwapped
assert _words[0].value == int.from_bytes(bytes(_words), _sys.byteorder)

# Field assignment copies encoded instances; only numeric inputs are converted.
for _base in (ctypes.Structure, ctypes.Union):
for _field_type in (_swapped, IndexedSwapped):

class EndianField(_base):
_fields_ = [("word", _field_type)]

_value = _field_type(0x01020304)
_aggregate = EndianField(_value)
assert bytes(_aggregate) == bytes(_value)
_field = EndianField.from_buffer_copy(bytes(_value)).word
assert getattr(_field, "value", _field) == _value.value
if _field_type is IndexedSwapped:
_aggregate.word = 0x55667788
assert bytes(_aggregate) == bytes(IndexedSwapped(0x55667788))
Loading