Is there a guaranteed way to assert that a given raw pointer is aligned to some alignment value?
I looked at pointer's aligned_offset
function, but the docs state that it is permissible for it to give false negatives (always return usize::MAX
), and that correctness cannot depend on it.
I don't want to fiddle with the alignment at all, I just want to write an assertion that will panic if the pointer is unaligned. My motivation is that when using certain low-level CPU intrinsics passing a pointer not aligned to some boundary causes a CPU error, and I'd much rather get a Rust panic message pointing where the bug causing it is located than a SEGFAULT.
An example assertion (not correct according to aligned_offset
docs):
#[repr(align(64))]
struct A64(u8);
#[repr(align(32))]
struct A32(u8);
#[repr(align(8))]
struct A8(u8);
fn main() {
let a64 = [A64(0)];
let a32 = [A32(0)];
let a8 = [A8(0), A8(0)];
println!("Assert for 64 should pass...");
assert_alignment(&a64);
println!("Assert for 32 should pass...");
assert_alignment(&a32);
println!("Assert for 8, one of the following should fail:");
println!("- full array");
assert_alignment(&a8);
println!("- offset by 8");
assert_alignment(&a8[1..]);
}
fn assert_alignment<T>(a: &[T]) {
let ptr = a.as_ptr();
assert_eq!(ptr.align_offset(32), 0);
}
CodePudding user response:
Just to satisfy my own neuroses, I went and checked the the source of ptr::align_offset
.
There's a lot of careful work around edge cases (e.g. const
-evaluated it always returns usize::MAX
, similarly for a pointer to a zero-sized type, and it panics if alignment
is not a power of 2). But the crux of the implementation, for your purposes, is here: it takes (ptr as usize) % alignment == 0
to check if it's aligned.
There's then some more complexity to calculate the exact offset (which may not be possible), but that's not relevant for this question.
Therefore:
assert_eq!(ptr.align_offset(alignment), 0);
should be plenty for your assertion.
Incidentally, this proves that the current rust standard library cannot target anything that does not represent pointers as simple numerical addresses, otherwise this function would not work. In the unlikely situation that the rust standard library is ported to the Intel 8086 or some weird DSP that doesn't represent pointers in the expected way, this function would have to change. But really, do you care for that hypothetical that much?