Inspired by a previous post I wrote the following code
use std::ptr;
#[repr(C)]
pub struct Array<T> {
len: usize,
ptr: *mut T,
}
impl<T: Copy> Array<T> {
fn new(val: T, len: usize) -> Self {
// This fails miri run.
let mut vec = Vec::with_capacity(len);
vec.fill(val);
let data = vec.into_boxed_slice();
// This passes miri run.
// let data = vec![val; len].into_boxed_slice();
Self {
len: len as usize,
ptr: Box::into_raw(data).cast(),
}
}
}
impl<T> Drop for Array<T> {
fn drop(&mut self) {
let &mut Self { len, ptr } = self;
let slice = ptr::slice_from_raw_parts_mut(ptr, len);
let a = unsafe { Box::from_raw(slice) };
std::mem::drop(a);
}
}
fn main() {
let mut _o = Array::new(14, 3);
}
If I use the vec![]
macro miri runs fine. If I use Vec::with_capacity()
and Vec::fill()
miri reports UB.
cargo +nightly miri run
Preparing a sysroot for Miri (target: x86_64-unknown-linux-gnu)... done
Finished dev [unoptimized + debuginfo] target(s) in 0.01s
Running `/home/johannes/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/bin/cargo-miri runner target/miri/x86_64-unknown-linux-gnu/debug/rust_test`
error: Undefined Behavior: out-of-bounds pointer use: 0x4[noalloc] is a dangling pointer (it has no provenance)
--> /home/johannes/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/alloc/src/boxed.rs:1007:9
|
1007 | Box(unsafe { Unique::new_unchecked(raw) }, alloc)
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ out-of-bounds pointer use: 0x4[noalloc] is a dangling pointer (it has no provenance)
|
= 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
= note: BACKTRACE:
= note: inside `std::boxed::Box::<[i32]>::from_raw_in` at /home/johannes/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/alloc/src/boxed.rs:1007:9: 1007:58
= note: inside `std::boxed::Box::<[i32]>::from_raw` at /home/johannes/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/alloc/src/boxed.rs:951:18: 951:48
note: inside `<Array<i32> as std::ops::Drop>::drop`
--> src/main.rs:30:26
|
30 | let a = unsafe { Box::from_raw(slice) };
| ^^^^^^^^^^^^^^^^^^^^
= note: inside `std::ptr::drop_in_place::<Array<i32>> - shim(Some(Array<i32>))` at /home/johannes/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/core/src/ptr/mod.rs:497:1: 497:56
note: inside `main`
--> src/main.rs:37:1
|
37 | }
| ^
note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace
error: aborting due to previous error
Can you help me understand this? Are both wrong and one just doesn't trigger the problem in miri or is there actaually a difference between these two?