Is it UB to byte-copy memory containing repr(C) structs with padding?
⚓ Rust 📅 2026-01-18 👤 surdeus 👁️ 7Hi,
I have a large contiguous block of memory (in reality mmap’d shared memory; here simplified as a u8 array). Into this memory I write several different #[repr(C)] structs sequentially using std::ptr::write::<T>(). Some of these structs may contain implicit padding.
Later, I want to copy the used portion of the memory as raw bytes (just a byte-for-byte copy).
My concern is the following:
#[repr(C)]structs may contain implicit padding.- Padding bytes are allowed to be uninitialized.
std::ptr::write::<T>()will cause theu8array to contain uninitialized bytes as well, despite being initialized before.- Copying the memory as
u8would read those padding bytes. - Reading uninitialized memory is UB.
Is this reasoning correct? If so, what is the correct way to handle this pattern?
Example
use std::mem::{align_of, size_of};
use std::ptr;
#[repr(C)]
struct A {
x: u8,
y: u32,
}
#[repr(C)]
struct B {
a: u32,
b: u64,
}
fn align_up(off: usize, align: usize) -> usize {
(off + align - 1) & !(align - 1)
}
fn main() {
let mut region = [0u8; 1024];
let mut snapshot = [0u8; 1024];
let mut cursor = 0usize;
unsafe {
cursor = align_up(cursor, align_of::<A>());
ptr::write(region.as_mut_ptr().add(cursor) as *mut A, A { x: 1, y: 2 });
cursor += size_of::<A>();
cursor = align_up(cursor, align_of::<B>());
ptr::write(region.as_mut_ptr().add(cursor) as *mut B, B { a: 3, b: 4 });
cursor += size_of::<B>();
// Later: byte-copy the populated prefix
ptr::copy_nonoverlapping(region.as_ptr(), snapshot.as_mut_ptr(), cursor);
}
}
3 posts - 2 participants
🏷️ Rust_feed