Bab*_*bur 5 undefined-behavior rust
假设我们有一个结构,其所有字段都具有相同大小的类型:
struct Homogeneous {
a: u64,
b: u64,
c: u64,
d: u64
}
Run Code Online (Sandbox Code Playgroud)
我们有一种“安全”的方法来从字节数组构造它:
impl From<[u8; 32]> for Homogeneous {
fn from(slice: [u8; 32]) -> Self {
// helper macro to convert slice of u8s into u64
macro_rules! to_u64 {
($slice: expr, $at: expr) => {{
let ss = &$slice[$at..$at + 8];
let mut buf = [0u8; 8];
buf.copy_from_slice(&ss);
u64::from_ne_bytes(buf)
}};
}
Self {
a: to_u64!(bytes, 0),
b: to_u64!(bytes, 8),
c: to_u64!(bytes, 16),
d: to_u64!(bytes, 24),
}
}
}
Run Code Online (Sandbox Code Playgroud)
这一切都很好并且有效。问题是不安全的解决方案(使用transmute)是否更有效(安全?),以及反向转换是否不会由于优化编译器重新排序结构字段而导致 UB?
impl From<[u8; 32]> for Homogeneous {
fn from(slice: [u8; 32]) -> Self {
unsafe { std::mem::transmute(slice) };
}
}
impl From<Homogeneous> for [u8; 32] {
fn from(h: Homogeneous) -> Self {
unsafe { std::mem::transmute(h) }
}
}
Run Code Online (Sandbox Code Playgroud)
这些转换在我的 x86 处理器上使用 rust 1.57 编译器工作,我想知道它们是否总是工作,不管架构/编译器如何。
来自rustlang 参考:
默认情况下,结构体的内存布局是未定义的,以允许编译器优化(例如字段重新排序),但可以使用repr 属性进行修复。在任何一种情况下,字段都可以在相应的结构表达式中以任何顺序给出;生成的结构体值将始终具有相同的内存布局。
这意味着不能保证属性会按照您的意愿排列。因此,您必须在实施中确保它始终有效。
例如使用#[repr(c)]:
#[repr(c)]
struct Homogeneous {
a: u64,
b: u64,
c: u64,
d: u64
}
Run Code Online (Sandbox Code Playgroud)
Netwave已经回答了有关安全的部分问题。
对于“更高效”的部分,godbolt 来救援:
你的代码产生
<example::Homogeneous as core::convert::From<[u8; 32]>>::from:
mov rax, rdi
movups xmm0, xmmword ptr [rsi]
movups xmm1, xmmword ptr [rsi + 16]
movups xmmword ptr [rdi], xmm0
movups xmmword ptr [rdi + 16], xmm1
ret
Run Code Online (Sandbox Code Playgroud)
和
#[repr(C)]
pub struct HomogeneousC { a: u64, b: u64, c: u64, d: u64 }
impl From<[u8; 32]> for HomogeneousC {
fn from(bytes: [u8; 32]) -> Self {
unsafe { std::mem::transmute(bytes) }
}
}
Run Code Online (Sandbox Code Playgroud)
产量
<example::HomogeneousC as core::convert::From<[u8; 32]>>::from:
mov rax, rdi
movups xmm0, xmmword ptr [rsi]
movups xmm1, xmmword ptr [rsi + 16]
movups xmmword ptr [rdi + 16], xmm1
movups xmmword ptr [rdi], xmm0
ret
Run Code Online (Sandbox Code Playgroud)
因此,LLVM 很好地优化了安全版本的所有缺陷,它们可能具有大致相同的性能。
| 归档时间: |
|
| 查看次数: |
553 次 |
| 最近记录: |