If one is talking to a C library which has a packed struct .. how does one safely access the values in it? (Assume misaligned non-byte integers in the struct).
The easiest is to define every field as a byte array, as in [u8; 4]
for an u32
. Accessing a byte array can never be unaligned. You can define getters that convert them:
#[repr(C)]
struct MyStruct {
my_int: [u8; 4],
}
impl MyStruct {
fn get_my_int(&self) -> u32 {
u32::from_ne_bytes(self.my_int)
}
}
If it's packed (non-standard C extension), define the same struct with #[repr(packed)]
.
Alternatively, use std::ptr::read_unaligned
to read any type at any address.
Correct me if I’m wrong, but I think you’d need to combine it, so #[repr(C, packed)]
, otherwise e.g. the order of the fields is not specified.
Isn't that way overkill? Rust should do the right thing if you just copy a field value.
(Playground - I examined asm and llvm output)
#[repr(C, packed)]
struct MyStruct {
my_int: u32,
}
impl MyStruct {
#[inline(never)]
pub fn get_my_int(&self) -> u32 {
self.my_int
}
}
pub fn g() -> u32 {
let ms = MyStruct { my_int: 0 };
ms.get_my_int()
}
Getting something like this
%0 = bitcast %MyStruct* %self to i32*
%1 = load i32, i32* %0, align 1
ret i32 %1
An unaligned load - basically reading from that pointer with align 1, which looks correct.
(inline(never) has no function here - just to make sure it doesn't optimize the llvm output too much)
Straight field access works correctly, but you cannot take a reference to an unaligned field. Specifying them all as byte arrays makes it easier when you do want to take those references.
From @alice's simple and yet reliable solution, you can use (or rewrite yourself) a nice wrapper around these "integer-represented-by-an-unaligned-bag-of-bytes" pattern, such as the types from the ::zerocopy::byteorder
module
Maybe it's finally redundant now that we can take raw pointers correctly with the addr_of macro
We can take raw pointers without risking of UB, but not read them without read_unaligned()
.
This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.