Summary

Add two functions, ptr::read_unaligned and ptr::write_unaligned, which allows reading/writing to an unaligned pointer. All other functions that access memory (ptr::{read,write}, ptr::copy{_nonoverlapping}, etc) require that a pointer be suitably aligned for its type.

Motivation

One major use case is to make working with packed structs easier:


# #![allow(unused_variables)]
#fn main() {
#[repr(packed)]
struct Packed(u8, u16, u8);

let mut a = Packed(0, 1, 0);
unsafe {
    let b = ptr::read_unaligned(&a.1);
    ptr::write_unaligned(&mut a.1, b + 1);
}
#}

Other use cases generally involve parsing some file formats or network protocols that use unaligned values.

Detailed design

The implementation of these functions are simple wrappers around ptr::copy_nonoverlapping. The pointers are cast to u8 to ensure that LLVM does not make any assumptions about the alignment.


# #![allow(unused_variables)]
#fn main() {
pub unsafe fn read_unaligned<T>(p: *const T) -> T {
    let mut r = mem::uninitialized();
    ptr::copy_nonoverlapping(p as *const u8,
                             &mut r as *mut _ as *mut u8,
                             mem::size_of::<T>());
    r
}

pub unsafe fn write_unaligned<T>(p: *mut T, v: T) {
    ptr::copy_nonoverlapping(&v as *const _ as *const u8,
                             p as *mut u8,
                             mem::size_of::<T>());
}
#}

Drawbacks

There functions aren't stricly necessary since they are just convenience wrappers around ptr::copy_nonoverlapping.

Alternatives

We could simply not add these, however figuring out how to do unaligned access properly is extremely unintuitive: you need to cast the pointer to *mut u8 and then call ptr::copy_nonoverlapping.

Unresolved questions

None