在生锈中移动原始指针的目标是否安全

Is moving the target of a raw Pointer safe in rust

提问人:RedCrafter LP 提问时间:11/7/2023 更新时间:11/7/2023 访问量:59

问:

我正在 rust 中创建一个双向图,父指针是 rust 借用规则的一个明显问题,所以我使用了原始指针,这些指针理论上是安全的,因为父指针拥有子指针,不能在子指针之前删除。我唯一的问题(在我的脑海中)是图形何时移动。如果图形移动,则所有父指针都应无效,因为它们指向图形的旧位置。

但是通过示例测试向我展示了不同的结果。不仅在旧指针仍然有效的地方,调试器还在“注册>有效地址”中显示一个新条目,该条目将旧指针映射到新位置。 我的测试代码:

fn main() -> Result<()> {

    let m = test();
    println!("MT:{}, IT:{}, PTR_MT:{}", m.j, m.inner.i, unsafe {(*m.inner.parent).j});
    Ok(())
}


fn test() -> Box<MyType> {
    let mut mytype = MyType { inner: MyInnerType { parent: std::ptr::null_mut(), i: 5 }, j:69 };
    println!("MT:{}, IT:{}", mytype.j, mytype.inner.i);
    mytype.inner.parent = &mut mytype;

    Box::new(mytype)
} 


struct MyType {
    inner: MyInnerType,
    j:i32
}

struct MyInnerType {
    parent: *mut MyType,
    i:i32
}

此行为是否已定义,我可以依赖它工作吗?

Rust 未定义行为 原始指针

评论

1赞 cafce25 11/7/2023
您在 Playground 的 [TOOLS] 右上角的 [MIRI] 中编写它的方式会检测到 UB。 移动并使其所有引用和指针失效。Box::new(mytype)mytype
0赞 RedCrafter LP 11/7/2023
CAFCE25 谢谢,这回答了这个问题,而不是它是否是 UB。这给我留下了关于如何解决这个问题的问题。最好不要创建不相交的堆结构。更新所有指针是可能的,但我没有看到触发更新的可靠方法。
0赞 BallpointBen 11/7/2023
原始指针在您尝试取消引用之前是安全的,因此,如果您尝试隔离不安全点,则它将是原始指针被取消引用的位置。
0赞 RedCrafter LP 11/7/2023
我刚刚找到了一个非常简单的解决方案。我只是在堆上分配了根,并阻止了对所属框的任何访问,使指针的持续时间与树一样长。

答:

3赞 cdhowie 11/7/2023 #1

不,这是不安全的。它是不健全的,并表现出未定义的行为。“程序按预期工作”是一种可能的结果,但不是唯一的结果。

Box::new(mytype)移动到堆分配中,该堆分配不是 UB。但是,稍后的评估会导致 UB,因为指针目标已被移动。mytype*m.inner.parent

你通常应该避免在 Rust 中使用原始指针,除非你在它们之上实现一个安全的抽象,或者你正在使用 FFI,没有它们就无法完成你需要做的事情。