rust - 从 mut ref 创建的指针上过度激进的 noalias?
问题描述
考虑以下内容(在 Rust >= 1.54 上):
pub fn assign_refs(i: &mut u32, j: &mut u32) -> u32 {
*i = 42;
*j = 7;
*i
}
根据可变引用之间没有别名,这编译为:
mov dword ptr [rdi], 42
mov dword ptr [rsi], 7
mov eax, 42
ret
现在考虑:
pub fn assign_ptrs(i: *mut u32, j: *mut u32) -> u32 {
*unsafe {&mut *i} = 42;
*unsafe {&mut *j} = 7;
unsafe {*i}
}
(注意一次只存在一个可变引用,所以这不是未定义的行为 if i == j
)。
由于指针可能有别名,最后一个表达式必须重新加载:
mov dword ptr [rdi], 42
mov dword ptr [rsi], 7
mov eax, dword ptr [rdi]
ret
如果j
指向 ,则下一个示例是未定义的行为i
:
pub fn assign_undefined_behavior_if_same(i: &mut u32, j: *mut u32) -> u32 {
*i = 42;
*unsafe {&mut *j} = 7; // UB if j points to i, second mut ref.
*i
}
因此,它编译为与 相同的代码assign_refs
,返回“错误”值。
我的问题是关于:
pub fn assign_mixed(i: &mut u32, j: *mut u32) -> u32 {
*i = 42;
let i_ptr = i as *mut u32;
std::convert::identity(i); // *Not* a reborrow, a move and drop.
// i no longer exists.
// *i = 42; // use of moved value: `i`
// At this point, why not the same as assign_ptrs?
*unsafe {&mut *j} = 7;
// Assumes that i_ptr is not aliased just because it came from a &mut?
unsafe {*i_ptr}
}
这编译成与 相同的东西assign_refs
,我觉得这很令人惊讶。
唯一别名引用i
在函数中途结束。在那一点上,为什么i_ptr
和j
不一样对待,就好像我们在assign_ptrs
?指针允许别名,因此j
可以指向i
/i_ptr
并且 i
不再存在。
作为参考,可以这样称呼:
fn test() {
let mut i = 0;
let mut i_ref = &mut i;
let i_ptr = i_ref as *mut u32;
assign_mixed(i_ref, i_ptr);
}
这是过度激进的 noalias 传播吗?
解决方案
Rust 遵循来自 LLVMnoalias
的模型,请参阅Behavior认为 undefined:&mut T
这表明通过基于参数或返回值的指针值访问的内存位置在函数执行期间也不会通过不基于参数或返回值的指针值访问。此保证仅适用于在函数执行期间以任何方式修改的内存位置。返回值的属性还具有下面描述的附加语义。调用者与被调用者共同承担确保满足这些要求的责任。
因此,如果我理解正确,这意味着只是i: &mut u32
在参数列表中期望它应该没有别名。甚至使用辅助功能,例如:
pub unsafe fn assign_mixed(i: &mut u32, j: *mut u32) -> u32 {
aux(i, j)
}
pub unsafe fn aux(i: *mut u32, j: *mut u32) -> u32 {
*i = 42;
*j = 7;
*i
}
不会工作。
我认为拥有类似东西的唯一方法是使用UnsafeCell
如下:
use std::cell::UnsafeCell;
pub unsafe fn assign_mixed(i: &UnsafeCell<u32>, j: *mut u32) -> u32 {
*i.get() = 42;
*j = 7;
*i.get()
}
将产生所需的汇编代码。一定不要&mut UnsafeCell
用于此。
推荐阅读
- python - 覆盖键值对与为不同的键创建新的键值对
- autodesk-forge - Autodesk Forge:如何在 BOX 上存储 3D 模型
- javascript - 从具有 2 个属性的异步存储中获取密钥
- c# - 如何在适当的时候捕获潜在的 301 或 404 错误?
- mongodb - How to group the array based on another array value in mongodb
- javascript - 如何在“美国地图”JQuery 插件中为每个州添加可点击链接
- php - 网址路由不起作用 Rest Api codeigniter
- unix - badblocks:尝试确定设备大小时资源繁忙
- c++ - 设置套接字选项以减少 tcp 段之间的时间延迟
- python - 使用 2 个标识符合并数据帧