为什么这个指针算术(不读取或写入这些指针后面的数据)会导致段错误?
#![allow(dead_code,unused_variables)]
use std::cell::Cell;
struct Bar<T: ?Sized> {
a: Cell<usize>,
value: T,
}
unsafe fn foo<T: ?Sized>(v: &T) {
let fake: &Bar<T> = std::mem::zeroed();
// segfault on this line
// we are not reading or writing uninitialized data behind the reference,
// but only doing pointer arithmetic. We are not reading or writing
// uninitialized vtable, but only copy the vtable pointer.
let fake_val = &fake.value;
}
fn main() {
use std::any::Any;
let some_ref: &Any = &42 as &Any;
unsafe { foo(some_ref) };
}
输出:Segmentation fault
答案 0 :(得分:9)
在Rust,merely creating a dangling reference is undefined behavior!这允许编译器围绕引用执行一些积极的优化,否则这是不可能的。
在这种特殊情况下,编译器会生成code which calculates the offset for the field by using the align
value in the vtable。所以它试图取消引用导致段错误的vptr。
要拥有悬空指针,您不应使用引用,而应使用raw pointer。你可以毫无问题地悬挂原始指针!
let fake: *const Bar<T> = std::ptr::null();
答案 1 :(得分:1)
您在指定的行上取消引用空指针。您正在引用该值是正确的,但是在调试模式下,LLVM的rustc输出代码非常愚蠢。尝试在发布模式下运行它,你会看到可能优化器对你很友善,而且不再是段错误。
由于这是UB,请不要依赖于此代码。