断言指针与某个值对齐
Assert that a pointer is aligned to some value
是否有保证方法可以断言给定的原始指针与某个对齐值对齐?
我查看了 pointer 的 aligned_offset
函数,但是文档声明允许它给出假阴性(总是 return usize::MAX
),并且正确性不能依赖于它。
我根本不想 fiddle 对齐,我只是想写一个断言,如果指针未对齐,它会出现恐慌。我的动机是,当使用某些低级 CPU 内在函数传递一个未与某些边界对齐的指针时,会导致 CPU 错误,我宁愿收到一条 Rust 恐慌消息,指出导致它的错误所在位于 SEGFAULT 之外。
一个示例断言(根据 aligned_offset
文档不正确):
#[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);
}
为了满足自己的神经病,我去查看了ptr::align_offset
的the source。
围绕边缘情况有很多仔细的工作(例如 const
-总是评估它 returns usize::MAX
,类似于指向 zero-sized 类型的指针,并且如果 alignment
不是 2 的幂,它会恐慌)。但是,为了您的目的,实施的关键是 here:检查它是否对齐需要 (ptr as usize) % alignment == 0
。
Edit:
This PR is adding a ptr::is_aligned_to
function, which is much more readable and also safer and better reviewed than simply (ptr as usize) % alginment == 0
(though the core of it is still that logic).
然后计算准确的偏移量会更加复杂(这可能是不可能的),但这与这个问题无关。
因此:
assert_eq!(ptr.align_offset(alignment), 0);
对于您的断言应该足够了。
顺带一提,这证明当前的rust标准库不能针对任何不将指针表示为简单数字地址的东西,否则这个函数将无法运行。在 rust 标准库被移植到 Intel 8086 或一些不以预期方式表示指针的奇怪 DSP 的不太可能的情况下,这个函数将不得不改变。不过说真的,你真的那么在乎那个假设吗?
是否有保证方法可以断言给定的原始指针与某个对齐值对齐?
我查看了 pointer 的 aligned_offset
函数,但是文档声明允许它给出假阴性(总是 return usize::MAX
),并且正确性不能依赖于它。
我根本不想 fiddle 对齐,我只是想写一个断言,如果指针未对齐,它会出现恐慌。我的动机是,当使用某些低级 CPU 内在函数传递一个未与某些边界对齐的指针时,会导致 CPU 错误,我宁愿收到一条 Rust 恐慌消息,指出导致它的错误所在位于 SEGFAULT 之外。
一个示例断言(根据 aligned_offset
文档不正确):
#[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);
}
为了满足自己的神经病,我去查看了ptr::align_offset
的the source。
围绕边缘情况有很多仔细的工作(例如 const
-总是评估它 returns usize::MAX
,类似于指向 zero-sized 类型的指针,并且如果 alignment
不是 2 的幂,它会恐慌)。但是,为了您的目的,实施的关键是 here:检查它是否对齐需要 (ptr as usize) % alignment == 0
。
Edit: This PR is adding a
ptr::is_aligned_to
function, which is much more readable and also safer and better reviewed than simply(ptr as usize) % alginment == 0
(though the core of it is still that logic).
然后计算准确的偏移量会更加复杂(这可能是不可能的),但这与这个问题无关。
因此:
assert_eq!(ptr.align_offset(alignment), 0);
对于您的断言应该足够了。
顺带一提,这证明当前的rust标准库不能针对任何不将指针表示为简单数字地址的东西,否则这个函数将无法运行。在 rust 标准库被移植到 Intel 8086 或一些不以预期方式表示指针的奇怪 DSP 的不太可能的情况下,这个函数将不得不改变。不过说真的,你真的那么在乎那个假设吗?