2

I came across this strange phenomenon while playing with unsafe Rust. I think this code should make a segmentation fault but it does not. Am I missing something? I tried to set a pointer to a variable with a shorter lifetime and then dereference it.

// function that sets a pointer to a variable with a shorter lifetime
unsafe fn what(p: &mut *const i32) {
    let a = 2;
    *p = &a;
    //let addr = *p;    // I will talk about this later
    println!("inside: {}", **p);
}

fn main() {
    let mut p: *const i32 = 0 as *const i32;
    unsafe {
        what(&mut p);

        // I thought this line would make a segfault because 'a' goes out of scope at the end of the function making the address invalid
        println!("segfault? {}", *p);

        // Even more unsettling: I can increment the address and still dereference it.
        p = ((p as usize) + 1) as *const i32;
        println!("I'm definitely missing something: {}", *p);
    }
}

This program outputs:

inside: 2
segfault? {random number around 20000. probably uninitialized memory but why?}
I'm definitely missing something: {uninitialized memory}

If I uncomment the line

let addr = *p;

the second row becomes

segfault? 2

Why is there no segfault? Can the compiler extend the lifetime of a or the address p points at for safety? Am I missing some basic information about pointers in Rust?

Shepmaster
  • 388,571
  • 95
  • 1,107
  • 1,366

1 Answers1

8

This isn't unique to Rust. See:

TL;DR: you have lied to the compiler. Your unsafe block does not uphold the requirements of safe code. This means you have created undefined behavior and the program is allowed to do whatever it wants. That could mean:

  • it crashes (such as via a segfault)
  • it runs perfectly
  • it erases your hard drive
  • it empties your bank account
  • it generates nasal demons
  • it eats your laundry
  • etc.

Segfaults are never a guaranteed outcome. A segmentation fault occurs when you access memory that is outside of the chunk of memory your thread/process has. The memory of the stack is well inside of that chunk, so it's unlikely to trigger the case.

See also:

Shepmaster
  • 388,571
  • 95
  • 1,107
  • 1,366
  • 2
    Don't forget nasal demons – Brady Dean Dec 19 '18 at 21:11
  • 1
    “_A segmentation fault **generally** occurs when you access memory outside the chunk that your process has_”: You can leave out the “generally” since that is the exact definition of a segfault. Other conditions can cause the program to crash, but those are not segmentation faults. – Jmb Dec 20 '18 at 07:27
  • @Jmb Not true! `raise(11);` will raise a segmentation fault. – Sapphire_Brick Nov 10 '20 at 04:53