fn dangle() {
fn get_str<'a>(s: *const String) -> &'a str {
unsafe { &*s }
}
let s = String::from("hello");
let dangling = get_str(&s);
drop(s);
println!("Invalid str: {}", dangling);
}
#[test]
fn test() {
dangle(); // it should panic, but does not
}
fn main() {
dangle(); // panics
}
main()
正如我所料,该函数崩溃了。但为什么该test()
函数能够成功运行?
正如本页所述,您的使用
unsafe
是不合理的(这是在问题中故意为之),因此导致未定义的行为。未定义的行为并不意味着代码必然会失败或崩溃。相反,它可以做任何事情,包括完美运行!在我的计算机上,主程序不会崩溃;它只是显示一个奇怪的字符串,在测试时也不会崩溃。即使在我的计算机上,指针没有指向无法访问的地址
drop()
,但此地址的字节已被重新用于其他内容,这在发送到标准输出时看起来不正确。此行为可能会不时发生变化,具体取决于系统中的任何内容(系统、编译器版本……)。这就是为什么必须避免使用不健全的代码;我们只能偶然发现并修复问题(如果它表现出明显的错误行为,例如恐慌)。另一方面,如果问题只是导致数据损坏,那么它可能会在执行过程中很晚才被发现,而且很难找到问题的真正原因(这里是悬空指针)。这种情况在 C 中相当常见。安全 Rust 可以防止这些陷阱发生;不安全的 Rust 则要求开发人员坚持某些保证。
@prog-fh 说什么。
我只是想补充一点,在使用
unsafe
代码时,强烈建议miri
在测试期间使用。miri
是一款专门检测不合理代码的 linter。它不能保证能找到所有代码,但在这方面它表现得相当不错。要使用 检查代码
miri
,请运行:然后,您会收到以下错误: