In C, taking the address of a packed field is allowed, even though the resulting pointer may be unaligned. The following program simply computes the byte offset of a field inside a packed struct by subtracting two addresses.
However, C2Rust generates Rust code that creates a reference to the packed field (&mut p.b), which is not allowed in Rust because packed struct fields may be unaligned. As a result, the generated code fails to compile with an unaligned reference error.
Reproducer
#include <stdint.h>
struct __attribute__((packed)) Packed {
uint8_t a;
uint32_t b;
};
int main(void) {
struct Packed p = {0};
int offset = (int)((uintptr_t)&p.b - (uintptr_t)&p);
return offset;
}
Transpiled Rust
#![allow(
dead_code,
non_camel_case_types,
non_snake_case,
non_upper_case_globals,
unused_assignments,
unused_mut
)]
pub type __uint8_t = u8;
pub type __uint32_t = u32;
pub type uint8_t = __uint8_t;
pub type uint32_t = __uint32_t;
pub type uintptr_t = usize;
#[derive(Copy, Clone)]
#[repr(C, packed)]
pub struct Packed {
pub a: uint8_t,
pub b: uint32_t,
}
unsafe fn main_0() -> ::core::ffi::c_int {
let mut p: Packed = {
let mut init = Packed { a: 0 as uint8_t, b: 0 };
init
};
let mut offset: ::core::ffi::c_int = (&mut p.b as *mut uint32_t as uintptr_t)
.wrapping_sub(&mut p as *mut Packed as uintptr_t) as ::core::ffi::c_int;
return offset;
}
pub fn main() {
unsafe { ::std::process::exit(main_0() as i32) }
}
Observed Behavior
The generated Rust code fails to compile:
error: reference to packed field is unaligned
This happens because the generated code creates a reference to a packed field:
Creating references to packed fields is undefined behavior in Rust.
Environment
- c2rust version: v0.21.0
- platform: Ubuntu 24.04
- Rust: nightly-2022-08-08
- Clang version: 17.0.6