Why is this pointer arithmetic (without reading or writing data behind these pointers) the cause of a segfault?
#![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)
Output: Segmentation fault
In Rust, merely creating a dangling reference is undefined behavior! This allows the compiler to perform some aggressive optimizations around references, that wouldn't be possible otherwise.
In this particular case, the compiler generates code which calculates the offset for the field by using the align
value in the vtable. So it tries to dereference the vptr which causes the segfault.
To have dangling pointer, you shouldn't use a reference, but a raw pointer. You can have dangling raw pointers without a problem!
let fake: *const Bar<T> = std::ptr::null();
You are dereferencing a null pointer on the line you indicated. You are correct that you are taking a reference to that value, but the code that rustc outputs for LLVM is very stupid in debug mode. Try running this in release mode, and you'll see that probably the optimizer will be kind to you and this will no longer segfault.
Since this is UB, please don't depend on this for real code.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With