Consider this example:
fn socket_addr_to_sockaddr() -> libc::sockaddr_storage {
let mut storage: libc::sockaddr_storage = unsafe { std::mem::zeroed() };
let sin: libc::sockaddr_in = unsafe { std::mem::zeroed() };
unsafe {
let sin_ptr = &sin as *const libc::sockaddr_in as *const libc::sockaddr;
let storage_ptr = &mut storage as *mut libc::sockaddr_storage as *mut libc::sockaddr;
std::ptr::copy_nonoverlapping(sin_ptr, storage_ptr, 1); // #1
}
storage
}
fn main() {
socket_addr_to_sockaddr();
}
The layout of libc::sockaddr_in
, libc::sockaddr_storage
, and libc::sockaddr
are respectively:
// size = 16 (0x10), align = 0x4
pub struct sockaddr_in {
pub sin_len: u8,
pub sin_family: u8,
pub sin_port: u16,
pub sin_addr: in_addr,
pub sin_zero: [i8; 8],
}
// size = 128 (0x80), align = 0x8
pub struct sockaddr_storage {
pub ss_len: u8,
pub ss_family: u8,
__ss_pad1: [u8; 6],
__ss_align: i64,
__ss_pad2: [u8; 112],
}
// size = 16 (0x10), align = 0x1
pub struct sockaddr {
pub sa_len: u8,
pub sa_family: u8,
pub sa_data: [i8; 14],
}
The alignment of sockaddr
is weaker than that of sockaddr_in
and sockaddr_storage
, so converting the pointer to the latter types to the pointer to sockaddr
does not result in misaligned pointers.
Q1:
Does #1
cause UB
?
Q2:
if change #1
to *storage_ptr = *sin_ptr
, does it cause UB
?
In C standard, it says:
A pointer to void shall have the same representation and alignment requirements as a pointer to a character type. Similarly, pointers to qualified or unqualified versions of compatible types shall have the same representation and alignment requirements. All pointers to structure types shall have the same representation and alignment requirements as each other. All pointers to union types shall have the same representation and alignment requirements as each other. Pointers to other types need not have the same representation or alignment requirements.
So, the result of the pointer cast is already ill-formed. I don't know whether such casting is valid in Rust.