Why this `set_null` function is unsound?

Running the function itself doesn't encounter any unexpected behavior, but Miri says there is UB. Where is it and what's the correct way? Thanks.

fn set_null<T: ?Sized>(ptr: *mut T) -> *mut T {
    unsafe { ptr.byte_sub(ptr as *const () as usize) }
}
error: Undefined Behavior: out-of-bounds pointer arithmetic: expected a pointer to the end of 147684 bytes of memory, but got alloc761 which is at the beginning of the allocation
 --> src/main.rs:7:14
  |
7 |     unsafe { ptr.byte_sub(ptr as *const () as usize) }
  |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ out-of-bounds pointer arithmetic: expected a pointer to the end of 147684 bytes of memory, but got alloc761 which is at the beginning of the allocation
  |
  = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior
  = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information
help: alloc761 was allocated here:
 --> src/main.rs:2:9
  |
2 |     let mut a = 10;
  |         ^^^^^
  = note: BACKTRACE (of the first span):
  = note: inside `set_null::<i32>` at src/main.rs:7:14: 7:53
note: inside `main`
 --> src/main.rs:3:5
  |
3 |     set_null(&mut a);
  |     ^^^^^^^^^^^^^^^^

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

here in the docs it says that the resulting pointer has to stay in bounds of the object which your use doesn't. the docs also suggest using wrapping_sub as that doesn't have those requirements.

Thanks!

1 Like

pointers in rust are not just memory addresses, they also have additional information attached to them called "provenance".

I suggest you read the following materials for more details.

1 Like

Thanks, I'll read them later.

2 Likes