Unsafe 3 @orlp @Noratrieb
Warning: this quiz is still "work-in-progress", some questions might not have good explanations (or any at all), formatting/structure/titles/etc are not final, and so on. You might want to return here on a later date.
Note: the question is whether the code, as executed, is UB or whether it is sound. When the snippet has UB, explain exactly where it is UB and why.
fn main() {
let mut v = vec![0_u8; 10];
// SAFETY: The vec has 10 elements, so 1 and 2 are in bounds.
// The two elements are distinct, so we are not overlapping.
unsafe {
let r1: *mut u8 = v.as_mut_ptr().add(1);
let r2: *mut u8 = v.as_mut_ptr().add(2);
*r1 = 10;
*r2 = 10;
}
}
fn main() {
let mut v = vec![0_u8; 10];
// SAFETY: The vec has 10 elements, so 1 and 2 are in bounds.
// The two elements are distinct, so we are not overlapping.
unsafe {
let r1: *mut u8 = v.get_unchecked_mut(1);
let r2: *mut u8 = v.get_unchecked_mut(2);
*r1 = 10;
*r2 = 10;
}
}
Solution
Example 1 is sound, example 2 is UB.
error: Undefined Behavior: attempting a write access using <2620> at alloc1189[0x1], but that tag does not exist in the borrow stack for this location
--> examples/unsafe_3_2.rs:9:9
|
9 | *r1 = 10;
| ^^^^^^^^
| |
| attempting a write access using <2620> at alloc1189[0x1], but that tag does not exist in the borrow stack for this location
| this error occurs as part of an access at alloc1189[0x1..0x2]
|
= 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: <2620> was created by a SharedReadWrite retag at offsets [0x1..0x2]
--> examples/unsafe_3_2.rs:7:27
|
7 | let r1: *mut u8 = v.get_unchecked_mut(1);
| ^^^^^^^^^^^^^^^^^^^^^^
help: <2620> was later invalidated at offsets [0x0..0xa] by a Unique retag
--> examples/unsafe_3_2.rs:8:27
|
8 | let r2: *mut u8 = v.get_unchecked_mut(2);
| ^^^^^^^^^^^^^^^^^^^^^^
= note: BACKTRACE (of the first span):
= note: inside `main` at examples/unsafe_3_2.rs:9:9: 9:17
note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace
error: aborting due to 1 previous error
v.as_mut_pointer()
refers to Vec::as_mut_ptr(v)
, which only creates a &mut
reference to the vec itself.
v.get_unchecked_mut()
comes from an implicit dereference to a slice, referring to <[T]>::get_unchecked_mut(Vec::deref(v))
, creating a &mut
to all slice elements.
When doing the deref for creating r2
, this full &mut
invalidates r1
.