为什么指针算术是段错误的原因?

时间:2017-09-06 21:44:37

标签: rust

为什么这个指针算术(不读取或写入这些指针后面的数据)会导致段错误?

#![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) };
}

On Playground

输出:Segmentation fault

2 个答案:

答案 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,请不要依赖于此代码。