Skip to content

Unexpected undefined behaviour when dereferencing pointer to struct casted from pointer to first member #4055

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
jrmuizel opened this issue Nov 24, 2024 · 1 comment

Comments

@jrmuizel
Copy link

Running the following test gives an Undefined Behaviour error

#[test]
fn from_ref_raw() {
    #[repr(C)]
    #[derive(Default)]
    struct Bar {
        x: i32,
        y: i32,
    }
    unsafe {
        use std::alloc::{Layout, alloc, dealloc};
        let p: *mut Bar = alloc(Layout::new::<Bar>()) as *mut Bar;
        std::ptr::write(p, Bar::default());
        let px = std::ptr::addr_of!((&*p).x);
        let k = px as *const Bar;
        (&*k).x;
        dealloc(p as *mut u8, Layout::new::<Bar>());
    }
}
test from_ref_raw ... error: Undefined Behavior: trying to retag from <262992> for SharedReadOnly permission at alloc104040[0x4], but that tag does not exist in the borrow stack for this location
  --> src/lib.rs:18:9
   |
18 |         (&*k).x;
   |         ^^^^^
   |         |
   |         trying to retag from <262992> for SharedReadOnly permission at alloc104040[0x4], but that tag does not exist in the borrow stack for this location
   |         this error occurs as part of retag at alloc104040[0x0..0x8]
   |
   = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental
   = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information
help: <262992> was created by a SharedReadOnly retag at offsets [0x0..0x4]
  --> src/lib.rs:16:18
   |
16 |         let px = addr_of!((&*p).x);
   |                  ^^^^^^^^^^^^^^^^^
   = note: BACKTRACE (of the first span) on thread `from_ref_raw`:
   = note: inside `from_ref_raw` at src/lib.rs:18:9: 18:14
note: inside closure
  --> src/lib.rs:5:18
   |
4  | #[test]
   | ------- in this procedural macro expansion
5  | fn from_ref_raw() {
   |                  ^
   = note: this error originates in the macro `addr_of` which comes from the expansion of the attribute macro `test` (in Nightly builds, run with -Z macro-backtrace for more info)

note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace

I don't understand why this is undefined behaviour. When run with MIRIFLAGS="-Zmiri-tree-borrows" I do not get the undefined behaviour error.

Interestingly, if I remove the y field from the struct the error goes away.

@saethlin
Copy link
Member

saethlin commented Nov 24, 2024

You are trying to do the &Header pattern, you can read this issue for some lengthy discussion on the matter rust-lang/unsafe-code-guidelines#256

The fact that Stacked Borrows forbids this is a known obstacle with the model, and one of the motivations for Tree Borrows.

(note that in the diagnostic your tag exists for bytes 0..4 and that is an exclusive range. It does not include byte 4. The UB happens starting at offset 4)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants