1
Fork 0

properly track why we checked whether a pointer is in-bounds

also simplify the in-bounds checking in Miri's borrow trackers
This commit is contained in:
Ralf Jung 2023-08-01 17:03:19 +02:00
parent 7d5886504c
commit 8496292dda
44 changed files with 130 additions and 122 deletions

View file

@ -282,7 +282,7 @@ const_eval_pointer_out_of_bounds =
*[many] bytes *[many] bytes
} starting at offset {$ptr_offset} is out-of-bounds } starting at offset {$ptr_offset} is out-of-bounds
const_eval_pointer_use_after_free = const_eval_pointer_use_after_free =
pointer to {$allocation} was dereferenced after this allocation got freed {$bad_pointer_message}: {$alloc_id} has been freed, so this pointer is dangling
const_eval_ptr_as_bytes_1 = const_eval_ptr_as_bytes_1 =
this code performed an operation that depends on the underlying bytes representing a pointer this code performed an operation that depends on the underlying bytes representing a pointer
const_eval_ptr_as_bytes_2 = const_eval_ptr_as_bytes_2 =

View file

@ -492,7 +492,7 @@ impl<'a> ReportErrorExt for UndefinedBehaviorInfo<'a> {
InvalidMeta(InvalidMetaKind::SliceTooBig) => const_eval_invalid_meta_slice, InvalidMeta(InvalidMetaKind::SliceTooBig) => const_eval_invalid_meta_slice,
InvalidMeta(InvalidMetaKind::TooBig) => const_eval_invalid_meta, InvalidMeta(InvalidMetaKind::TooBig) => const_eval_invalid_meta,
UnterminatedCString(_) => const_eval_unterminated_c_string, UnterminatedCString(_) => const_eval_unterminated_c_string,
PointerUseAfterFree(_) => const_eval_pointer_use_after_free, PointerUseAfterFree(_, _) => const_eval_pointer_use_after_free,
PointerOutOfBounds { ptr_size: Size::ZERO, .. } => const_eval_zst_pointer_out_of_bounds, PointerOutOfBounds { ptr_size: Size::ZERO, .. } => const_eval_zst_pointer_out_of_bounds,
PointerOutOfBounds { .. } => const_eval_pointer_out_of_bounds, PointerOutOfBounds { .. } => const_eval_pointer_out_of_bounds,
DanglingIntPointer(0, _) => const_eval_dangling_null_pointer, DanglingIntPointer(0, _) => const_eval_dangling_null_pointer,
@ -545,8 +545,10 @@ impl<'a> ReportErrorExt for UndefinedBehaviorInfo<'a> {
UnterminatedCString(ptr) | InvalidFunctionPointer(ptr) | InvalidVTablePointer(ptr) => { UnterminatedCString(ptr) | InvalidFunctionPointer(ptr) | InvalidVTablePointer(ptr) => {
builder.set_arg("pointer", ptr); builder.set_arg("pointer", ptr);
} }
PointerUseAfterFree(allocation) => { PointerUseAfterFree(alloc_id, msg) => {
builder.set_arg("allocation", allocation); builder
.set_arg("alloc_id", alloc_id)
.set_arg("bad_pointer_message", bad_pointer_message(msg, handler));
} }
PointerOutOfBounds { alloc_id, alloc_size, ptr_offset, ptr_size, msg } => { PointerOutOfBounds { alloc_id, alloc_size, ptr_offset, ptr_size, msg } => {
builder builder

View file

@ -317,7 +317,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
kind = "static_mem" kind = "static_mem"
) )
} }
None => err_ub!(PointerUseAfterFree(alloc_id)), None => err_ub!(PointerUseAfterFree(alloc_id, CheckInAllocMsg::MemoryAccessTest)),
} }
.into()); .into());
}; };
@ -380,7 +380,8 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
M::enforce_alignment(self), M::enforce_alignment(self),
CheckInAllocMsg::MemoryAccessTest, CheckInAllocMsg::MemoryAccessTest,
|alloc_id, offset, prov| { |alloc_id, offset, prov| {
let (size, align) = self.get_live_alloc_size_and_align(alloc_id)?; let (size, align) = self
.get_live_alloc_size_and_align(alloc_id, CheckInAllocMsg::MemoryAccessTest)?;
Ok((size, align, (alloc_id, offset, prov))) Ok((size, align, (alloc_id, offset, prov)))
}, },
) )
@ -404,7 +405,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
CheckAlignment::Error, CheckAlignment::Error,
msg, msg,
|alloc_id, _, _| { |alloc_id, _, _| {
let (size, align) = self.get_live_alloc_size_and_align(alloc_id)?; let (size, align) = self.get_live_alloc_size_and_align(alloc_id, msg)?;
Ok((size, align, ())) Ok((size, align, ()))
}, },
)?; )?;
@ -414,7 +415,9 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
/// Low-level helper function to check if a ptr is in-bounds and potentially return a reference /// Low-level helper function to check if a ptr is in-bounds and potentially return a reference
/// to the allocation it points to. Supports both shared and mutable references, as the actual /// to the allocation it points to. Supports both shared and mutable references, as the actual
/// checking is offloaded to a helper closure. `align` defines whether and which alignment check /// checking is offloaded to a helper closure. `align` defines whether and which alignment check
/// is done. Returns `None` for size 0, and otherwise `Some` of what `alloc_size` returned. /// is done.
///
/// If this returns `None`, the size is 0; it can however return `Some` even for size 0.
fn check_and_deref_ptr<T>( fn check_and_deref_ptr<T>(
&self, &self,
ptr: Pointer<Option<M::Provenance>>, ptr: Pointer<Option<M::Provenance>>,
@ -515,7 +518,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
} }
Some(GlobalAlloc::Function(..)) => throw_ub!(DerefFunctionPointer(id)), Some(GlobalAlloc::Function(..)) => throw_ub!(DerefFunctionPointer(id)),
Some(GlobalAlloc::VTable(..)) => throw_ub!(DerefVTablePointer(id)), Some(GlobalAlloc::VTable(..)) => throw_ub!(DerefVTablePointer(id)),
None => throw_ub!(PointerUseAfterFree(id)), None => throw_ub!(PointerUseAfterFree(id, CheckInAllocMsg::MemoryAccessTest)),
Some(GlobalAlloc::Static(def_id)) => { Some(GlobalAlloc::Static(def_id)) => {
assert!(self.tcx.is_static(def_id)); assert!(self.tcx.is_static(def_id));
assert!(!self.tcx.is_thread_local_static(def_id)); assert!(!self.tcx.is_thread_local_static(def_id));
@ -761,11 +764,15 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
} }
} }
/// Obtain the size and alignment of a live allocation. /// Obtain the size and alignment of a *live* allocation.
pub fn get_live_alloc_size_and_align(&self, id: AllocId) -> InterpResult<'tcx, (Size, Align)> { fn get_live_alloc_size_and_align(
&self,
id: AllocId,
msg: CheckInAllocMsg,
) -> InterpResult<'tcx, (Size, Align)> {
let (size, align, kind) = self.get_alloc_info(id); let (size, align, kind) = self.get_alloc_info(id);
if matches!(kind, AllocKind::Dead) { if matches!(kind, AllocKind::Dead) {
throw_ub!(PointerUseAfterFree(id)) throw_ub!(PointerUseAfterFree(id, msg))
} }
Ok((size, align)) Ok((size, align))
} }

View file

@ -224,8 +224,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
Len(place) => { Len(place) => {
let src = self.eval_place(place)?; let src = self.eval_place(place)?;
let op = self.place_to_op(&src)?; let len = src.len(self)?;
let len = op.len(self)?;
self.write_scalar(Scalar::from_target_usize(len, self), &dest)?; self.write_scalar(Scalar::from_target_usize(len, self), &dest)?;
} }

View file

@ -282,8 +282,8 @@ pub enum UndefinedBehaviorInfo<'a> {
InvalidMeta(InvalidMetaKind), InvalidMeta(InvalidMetaKind),
/// Reading a C string that does not end within its allocation. /// Reading a C string that does not end within its allocation.
UnterminatedCString(Pointer), UnterminatedCString(Pointer),
/// Dereferencing a dangling pointer after it got freed. /// Using a pointer after it got freed.
PointerUseAfterFree(AllocId), PointerUseAfterFree(AllocId, CheckInAllocMsg),
/// Used a pointer outside the bounds it is valid for. /// Used a pointer outside the bounds it is valid for.
/// (If `ptr_size > 0`, determines the size of the memory range that was expected to be in-bounds.) /// (If `ptr_size > 0`, determines the size of the memory range that was expected to be in-bounds.)
PointerOutOfBounds { PointerOutOfBounds {

View file

@ -18,7 +18,7 @@ use rustc_middle::ty::{
layout::{HasParamEnv, LayoutOf}, layout::{HasParamEnv, LayoutOf},
Ty, Ty,
}; };
use rustc_target::abi::{Abi, Size}; use rustc_target::abi::{Abi, Align, Size};
use crate::borrow_tracker::{ use crate::borrow_tracker::{
stacked_borrows::diagnostics::{AllocHistory, DiagnosticCx, DiagnosticCxBuilder}, stacked_borrows::diagnostics::{AllocHistory, DiagnosticCx, DiagnosticCxBuilder},
@ -619,6 +619,8 @@ trait EvalContextPrivExt<'mir: 'ecx, 'tcx: 'mir, 'ecx>: crate::MiriInterpCxExt<'
retag_info: RetagInfo, // diagnostics info about this retag retag_info: RetagInfo, // diagnostics info about this retag
) -> InterpResult<'tcx, Option<AllocId>> { ) -> InterpResult<'tcx, Option<AllocId>> {
let this = self.eval_context_mut(); let this = self.eval_context_mut();
// Ensure we bail out if the pointer goes out-of-bounds (see miri#1050).
this.check_ptr_access_align(place.ptr, size, Align::ONE, CheckInAllocMsg::InboundsTest)?;
// It is crucial that this gets called on all code paths, to ensure we track tag creation. // It is crucial that this gets called on all code paths, to ensure we track tag creation.
let log_creation = |this: &MiriInterpCx<'mir, 'tcx>, let log_creation = |this: &MiriInterpCx<'mir, 'tcx>,
@ -707,18 +709,6 @@ trait EvalContextPrivExt<'mir: 'ecx, 'tcx: 'mir, 'ecx>: crate::MiriInterpCxExt<'
let (alloc_id, base_offset, orig_tag) = this.ptr_get_alloc_id(place.ptr)?; let (alloc_id, base_offset, orig_tag) = this.ptr_get_alloc_id(place.ptr)?;
log_creation(this, Some((alloc_id, base_offset, orig_tag)))?; log_creation(this, Some((alloc_id, base_offset, orig_tag)))?;
// Ensure we bail out if the pointer goes out-of-bounds (see miri#1050).
let (alloc_size, _) = this.get_live_alloc_size_and_align(alloc_id)?;
if base_offset + size > alloc_size {
throw_ub!(PointerOutOfBounds {
alloc_id,
alloc_size,
ptr_offset: this.target_usize_to_isize(base_offset.bytes()),
ptr_size: size,
msg: CheckInAllocMsg::InboundsTest
});
}
trace!( trace!(
"reborrow: reference {:?} derived from {:?} (pointee {}): {:?}, size {}", "reborrow: reference {:?} derived from {:?} (pointee {}): {:?}, size {}",
new_tag, new_tag,

View file

@ -1,6 +1,6 @@
use log::trace; use log::trace;
use rustc_target::abi::{Abi, Size}; use rustc_target::abi::{Abi, Align, Size};
use crate::borrow_tracker::{AccessKind, GlobalStateInner, ProtectorKind, RetagFields}; use crate::borrow_tracker::{AccessKind, GlobalStateInner, ProtectorKind, RetagFields};
use rustc_middle::{ use rustc_middle::{
@ -182,6 +182,8 @@ trait EvalContextPrivExt<'mir: 'ecx, 'tcx: 'mir, 'ecx>: crate::MiriInterpCxExt<'
new_tag: BorTag, new_tag: BorTag,
) -> InterpResult<'tcx, Option<(AllocId, BorTag)>> { ) -> InterpResult<'tcx, Option<(AllocId, BorTag)>> {
let this = self.eval_context_mut(); let this = self.eval_context_mut();
// Ensure we bail out if the pointer goes out-of-bounds (see miri#1050).
this.check_ptr_access_align(place.ptr, ptr_size, Align::ONE, CheckInAllocMsg::InboundsTest)?;
// It is crucial that this gets called on all code paths, to ensure we track tag creation. // It is crucial that this gets called on all code paths, to ensure we track tag creation.
let log_creation = |this: &MiriInterpCx<'mir, 'tcx>, let log_creation = |this: &MiriInterpCx<'mir, 'tcx>,
@ -202,51 +204,33 @@ trait EvalContextPrivExt<'mir: 'ecx, 'tcx: 'mir, 'ecx>: crate::MiriInterpCxExt<'
}; };
trace!("Reborrow of size {:?}", ptr_size); trace!("Reborrow of size {:?}", ptr_size);
let (alloc_id, base_offset, parent_prov) = if ptr_size > Size::ZERO { let (alloc_id, base_offset, parent_prov) = match this.ptr_try_get_alloc_id(place.ptr) {
this.ptr_get_alloc_id(place.ptr)? Ok(data) => {
} else { // Unlike SB, we *do* a proper retag for size 0 if can identify the allocation.
match this.ptr_try_get_alloc_id(place.ptr) { // After all, the pointer may be lazily initialized outside this initial range.
Ok(data) => data, data
Err(_) => { },
// This pointer doesn't come with an AllocId, so there's no Err(_) => {
// memory to do retagging in. assert_eq!(ptr_size, Size::ZERO); // we did the deref check above, size has to be 0 here
trace!( // This pointer doesn't come with an AllocId, so there's no
"reborrow of size 0: reference {:?} derived from {:?} (pointee {})", // memory to do retagging in.
new_tag, trace!(
place.ptr, "reborrow of size 0: reference {:?} derived from {:?} (pointee {})",
place.layout.ty, new_tag,
); place.ptr,
log_creation(this, None)?; place.layout.ty,
return Ok(None); );
} log_creation(this, None)?;
return Ok(None);
} }
}; };
log_creation(this, Some((alloc_id, base_offset, parent_prov)))?;
let orig_tag = match parent_prov { let orig_tag = match parent_prov {
ProvenanceExtra::Wildcard => return Ok(None), // TODO: handle wildcard pointers ProvenanceExtra::Wildcard => return Ok(None), // TODO: handle wildcard pointers
ProvenanceExtra::Concrete(tag) => tag, ProvenanceExtra::Concrete(tag) => tag,
}; };
// Protection against trying to get a reference to a vtable:
// vtables do not have an alloc_extra so the call to
// `get_alloc_extra` that follows fails.
let (alloc_size, _align, alloc_kind) = this.get_alloc_info(alloc_id);
if ptr_size == Size::ZERO && !matches!(alloc_kind, AllocKind::LiveData) {
return Ok(Some((alloc_id, orig_tag)));
}
log_creation(this, Some((alloc_id, base_offset, parent_prov)))?;
// Ensure we bail out if the pointer goes out-of-bounds (see miri#1050).
if base_offset + ptr_size > alloc_size {
throw_ub!(PointerOutOfBounds {
alloc_id,
alloc_size,
ptr_offset: this.target_usize_to_isize(base_offset.bytes()),
ptr_size,
msg: CheckInAllocMsg::InboundsTest
});
}
trace!( trace!(
"reborrow: reference {:?} derived from {:?} (pointee {}): {:?}, size {}", "reborrow: reference {:?} derived from {:?} (pointee {}): {:?}, size {}",
new_tag, new_tag,

View file

@ -1,6 +1,6 @@
use std::alloc::{alloc, dealloc, Layout}; use std::alloc::{alloc, dealloc, Layout};
//@error-in-other-file: dereferenced after this allocation got freed //@error-in-other-file: has been freed
fn main() { fn main() {
unsafe { unsafe {

View file

@ -1,8 +1,8 @@
error: Undefined Behavior: pointer to ALLOC was dereferenced after this allocation got freed error: Undefined Behavior: memory access failed: ALLOC has been freed, so this pointer is dangling
--> RUSTLIB/alloc/src/alloc.rs:LL:CC --> RUSTLIB/alloc/src/alloc.rs:LL:CC
| |
LL | unsafe { __rust_dealloc(ptr, layout.size(), layout.align()) } LL | unsafe { __rust_dealloc(ptr, layout.size(), layout.align()) }
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ pointer to ALLOC was dereferenced after this allocation got freed | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ memory access failed: ALLOC has been freed, so this pointer is dangling
| |
= help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = 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: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information

View file

@ -4,6 +4,6 @@ fn main() {
unsafe { unsafe {
let x = alloc(Layout::from_size_align_unchecked(1, 1)); let x = alloc(Layout::from_size_align_unchecked(1, 1));
let _y = realloc(x, Layout::from_size_align_unchecked(1, 1), 1); let _y = realloc(x, Layout::from_size_align_unchecked(1, 1), 1);
let _z = *x; //~ ERROR: dereferenced after this allocation got freed let _z = *x; //~ ERROR: has been freed
} }
} }

View file

@ -1,8 +1,8 @@
error: Undefined Behavior: pointer to ALLOC was dereferenced after this allocation got freed error: Undefined Behavior: dereferencing pointer failed: ALLOC has been freed, so this pointer is dangling
--> $DIR/reallocate-change-alloc.rs:LL:CC --> $DIR/reallocate-change-alloc.rs:LL:CC
| |
LL | let _z = *x; LL | let _z = *x;
| ^^ pointer to ALLOC was dereferenced after this allocation got freed | ^^ dereferencing pointer failed: ALLOC has been freed, so this pointer is dangling
| |
= help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = 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: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information

View file

@ -1,6 +1,6 @@
use std::alloc::{alloc, dealloc, realloc, Layout}; use std::alloc::{alloc, dealloc, realloc, Layout};
//@error-in-other-file: dereferenced after this allocation got freed //@error-in-other-file: has been freed
fn main() { fn main() {
unsafe { unsafe {

View file

@ -1,8 +1,8 @@
error: Undefined Behavior: pointer to ALLOC was dereferenced after this allocation got freed error: Undefined Behavior: memory access failed: ALLOC has been freed, so this pointer is dangling
--> RUSTLIB/alloc/src/alloc.rs:LL:CC --> RUSTLIB/alloc/src/alloc.rs:LL:CC
| |
LL | unsafe { __rust_realloc(ptr, layout.size(), layout.align(), new_size) } LL | unsafe { __rust_realloc(ptr, layout.size(), layout.align(), new_size) }
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ pointer to ALLOC was dereferenced after this allocation got freed | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ memory access failed: ALLOC has been freed, so this pointer is dangling
| |
= help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = 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: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information

View file

@ -11,6 +11,6 @@ unsafe impl Send for SendRaw {}
fn main() { fn main() {
unsafe { unsafe {
let dangling_ptr = std::thread::spawn(|| SendRaw(&TLS as *const u8)).join().unwrap(); let dangling_ptr = std::thread::spawn(|| SendRaw(&TLS as *const u8)).join().unwrap();
let _val = *dangling_ptr.0; //~ ERROR: dereferenced after this allocation got freed let _val = *dangling_ptr.0; //~ ERROR: has been freed
} }
} }

View file

@ -1,8 +1,8 @@
error: Undefined Behavior: pointer to ALLOC was dereferenced after this allocation got freed error: Undefined Behavior: dereferencing pointer failed: ALLOC has been freed, so this pointer is dangling
--> $DIR/thread_local_static_dealloc.rs:LL:CC --> $DIR/thread_local_static_dealloc.rs:LL:CC
| |
LL | let _val = *dangling_ptr.0; LL | let _val = *dangling_ptr.0;
| ^^^^^^^^^^^^^^^ pointer to ALLOC was dereferenced after this allocation got freed | ^^^^^^^^^^^^^^^ dereferencing pointer failed: ALLOC has been freed, so this pointer is dangling
| |
= help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = 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: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information

View file

@ -7,6 +7,6 @@ fn main() {
let b = Box::new(42); let b = Box::new(42);
&*b as *const i32 &*b as *const i32
}; };
let x = unsafe { ptr::addr_of!(*p) }; //~ ERROR: dereferenced after this allocation got freed let x = unsafe { ptr::addr_of!(*p) }; //~ ERROR: has been freed
panic!("this should never print: {:?}", x); panic!("this should never print: {:?}", x);
} }

View file

@ -1,8 +1,8 @@
error: Undefined Behavior: pointer to ALLOC was dereferenced after this allocation got freed error: Undefined Behavior: dereferencing pointer failed: ALLOC has been freed, so this pointer is dangling
--> $DIR/dangling_pointer_addr_of.rs:LL:CC --> $DIR/dangling_pointer_addr_of.rs:LL:CC
| |
LL | let x = unsafe { ptr::addr_of!(*p) }; LL | let x = unsafe { ptr::addr_of!(*p) };
| ^^^^^^^^^^^^^^^^^ pointer to ALLOC was dereferenced after this allocation got freed | ^^^^^^^^^^^^^^^^^ dereferencing pointer failed: ALLOC has been freed, so this pointer is dangling
| |
= help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = 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: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information

View file

@ -6,6 +6,6 @@ fn main() {
let b = Box::new(42); let b = Box::new(42);
&*b as *const i32 &*b as *const i32
}; };
let x = unsafe { *p }; //~ ERROR: dereferenced after this allocation got freed let x = unsafe { *p }; //~ ERROR: has been freed
panic!("this should never print: {}", x); panic!("this should never print: {}", x);
} }

View file

@ -1,8 +1,8 @@
error: Undefined Behavior: pointer to ALLOC was dereferenced after this allocation got freed error: Undefined Behavior: dereferencing pointer failed: ALLOC has been freed, so this pointer is dangling
--> $DIR/dangling_pointer_deref.rs:LL:CC --> $DIR/dangling_pointer_deref.rs:LL:CC
| |
LL | let x = unsafe { *p }; LL | let x = unsafe { *p };
| ^^ pointer to ALLOC was dereferenced after this allocation got freed | ^^ dereferencing pointer failed: ALLOC has been freed, so this pointer is dangling
| |
= help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = 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: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information

View file

@ -0,0 +1,11 @@
// Make sure we find these even with many checks disabled.
//@compile-flags: -Zmiri-disable-alignment-check -Zmiri-disable-stacked-borrows -Zmiri-disable-validation
fn main() {
let p = {
let b = Box::new(42);
&*b as *const i32
};
let x = unsafe { p.offset(42) }; //~ ERROR: /out-of-bounds pointer arithmetic: .* has been freed/
panic!("this should never print: {:?}", x);
}

View file

@ -0,0 +1,15 @@
error: Undefined Behavior: out-of-bounds pointer arithmetic: ALLOC has been freed, so this pointer is dangling
--> $DIR/dangling_pointer_offset.rs:LL:CC
|
LL | let x = unsafe { p.offset(42) };
| ^^^^^^^^^^^^ out-of-bounds pointer arithmetic: ALLOC has been freed, so this pointer is dangling
|
= 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 `main` at $DIR/dangling_pointer_offset.rs:LL:CC
note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace
error: aborting due to previous error

View file

@ -7,7 +7,7 @@ fn main() {
&*b as *const i32 &*b as *const i32
}; };
unsafe { unsafe {
let _ = *p; //~ ERROR: dereferenced after this allocation got freed let _ = *p; //~ ERROR: has been freed
} }
panic!("this should never print"); panic!("this should never print");
} }

View file

@ -1,13 +1,13 @@
error: Undefined Behavior: pointer to ALLOC was dereferenced after this allocation got freed error: Undefined Behavior: dereferencing pointer failed: ALLOC has been freed, so this pointer is dangling
--> $DIR/dangling_pointer_deref_underscore.rs:LL:CC --> $DIR/dangling_pointer_project_underscore.rs:LL:CC
| |
LL | let _ = *p; LL | let _ = *p;
| ^^ pointer to ALLOC was dereferenced after this allocation got freed | ^^ dereferencing pointer failed: ALLOC has been freed, so this pointer is dangling
| |
= help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = 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: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information
= note: BACKTRACE: = note: BACKTRACE:
= note: inside `main` at $DIR/dangling_pointer_deref_underscore.rs:LL:CC = note: inside `main` at $DIR/dangling_pointer_project_underscore.rs:LL:CC
note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace

View file

@ -6,5 +6,5 @@ fn main() {
let b = Box::new(42); let b = Box::new(42);
&*b as *const i32 as *const () &*b as *const i32 as *const ()
}; };
let _x = unsafe { *p }; //~ ERROR: dereferenced after this allocation got freed let _x = unsafe { *p }; //~ ERROR: has been freed
} }

View file

@ -1,8 +1,8 @@
error: Undefined Behavior: pointer to ALLOC was dereferenced after this allocation got freed error: Undefined Behavior: dereferencing pointer failed: ALLOC has been freed, so this pointer is dangling
--> $DIR/dangling_zst_deref.rs:LL:CC --> $DIR/dangling_zst_deref.rs:LL:CC
| |
LL | let _x = unsafe { *p }; LL | let _x = unsafe { *p };
| ^^ pointer to ALLOC was dereferenced after this allocation got freed | ^^ dereferencing pointer failed: ALLOC has been freed, so this pointer is dangling
| |
= help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = 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: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information

View file

@ -8,7 +8,7 @@ unsafe fn make_ref<'a>(x: *mut i32) -> &'a mut i32 {
fn main() { fn main() {
unsafe { unsafe {
let x = make_ref(&mut 0); // The temporary storing "0" is deallocated at the ";"! let x = make_ref(&mut 0); // The temporary storing "0" is deallocated at the ";"!
let val = *x; //~ ERROR: dereferenced after this allocation got freed let val = *x; //~ ERROR: has been freed
println!("{}", val); println!("{}", val);
} }
} }

View file

@ -1,8 +1,8 @@
error: Undefined Behavior: pointer to ALLOC was dereferenced after this allocation got freed error: Undefined Behavior: dereferencing pointer failed: ALLOC has been freed, so this pointer is dangling
--> $DIR/stack_temporary.rs:LL:CC --> $DIR/stack_temporary.rs:LL:CC
| |
LL | let val = *x; LL | let val = *x;
| ^^ pointer to ALLOC was dereferenced after this allocation got freed | ^^ dereferencing pointer failed: ALLOC has been freed, so this pointer is dangling
| |
= help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = 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: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information

View file

@ -32,7 +32,7 @@ pub fn main() {
let ptr = ptr; // avoid field capturing let ptr = ptr; // avoid field capturing
// Also an error of the form: Data race detected between (1) Deallocate on thread `<unnamed>` and (2) Read on thread `<unnamed>` // Also an error of the form: Data race detected between (1) Deallocate on thread `<unnamed>` and (2) Read on thread `<unnamed>`
// but the invalid allocation is detected first. // but the invalid allocation is detected first.
*ptr.0 //~ ERROR: dereferenced after this allocation got freed *ptr.0 //~ ERROR: has been freed
}); });
j1.join().unwrap(); j1.join().unwrap();

View file

@ -1,8 +1,8 @@
error: Undefined Behavior: pointer to ALLOC was dereferenced after this allocation got freed error: Undefined Behavior: dereferencing pointer failed: ALLOC has been freed, so this pointer is dangling
--> $DIR/dealloc_read_race2.rs:LL:CC --> $DIR/dealloc_read_race2.rs:LL:CC
| |
LL | *ptr.0 LL | *ptr.0
| ^^^^^^ pointer to ALLOC was dereferenced after this allocation got freed | ^^^^^^ dereferencing pointer failed: ALLOC has been freed, so this pointer is dangling
| |
= help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = 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: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information

View file

@ -31,7 +31,7 @@ pub fn main() {
let ptr = ptr; // avoid field capturing let ptr = ptr; // avoid field capturing
// Also an error of the form: Data race detected between (1) Deallocate on thread `<unnamed>` and (2) Write on thread `<unnamed>` // Also an error of the form: Data race detected between (1) Deallocate on thread `<unnamed>` and (2) Write on thread `<unnamed>`
// but the invalid allocation is detected first. // but the invalid allocation is detected first.
*ptr.0 = 2; //~ ERROR: dereferenced after this allocation got freed *ptr.0 = 2; //~ ERROR: has been freed
}); });
j1.join().unwrap(); j1.join().unwrap();

View file

@ -1,8 +1,8 @@
error: Undefined Behavior: pointer to ALLOC was dereferenced after this allocation got freed error: Undefined Behavior: dereferencing pointer failed: ALLOC has been freed, so this pointer is dangling
--> $DIR/dealloc_write_race2.rs:LL:CC --> $DIR/dealloc_write_race2.rs:LL:CC
| |
LL | *ptr.0 = 2; LL | *ptr.0 = 2;
| ^^^^^^^^^^ pointer to ALLOC was dereferenced after this allocation got freed | ^^^^^^^^^^ dereferencing pointer failed: ALLOC has been freed, so this pointer is dangling
| |
= help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = 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: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information

View file

@ -20,5 +20,5 @@ fn main() {
let pointer = get_environ(); let pointer = get_environ();
let _x = unsafe { *pointer }; let _x = unsafe { *pointer };
std::env::set_var("FOO", "BAR"); std::env::set_var("FOO", "BAR");
let _y = unsafe { *pointer }; //~ ERROR: dereferenced after this allocation got freed let _y = unsafe { *pointer }; //~ ERROR: has been freed
} }

View file

@ -1,8 +1,8 @@
error: Undefined Behavior: pointer to ALLOC was dereferenced after this allocation got freed error: Undefined Behavior: dereferencing pointer failed: ALLOC has been freed, so this pointer is dangling
--> $DIR/environ-gets-deallocated.rs:LL:CC --> $DIR/environ-gets-deallocated.rs:LL:CC
| |
LL | let _y = unsafe { *pointer }; LL | let _y = unsafe { *pointer };
| ^^^^^^^^ pointer to ALLOC was dereferenced after this allocation got freed | ^^^^^^^^ dereferencing pointer failed: ALLOC has been freed, so this pointer is dangling
| |
= help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = 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: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information

View file

@ -13,7 +13,7 @@ fn firstn() -> impl Generator<Yield = u64, Return = ()> {
*num += 0; *num += 0;
yield *num; yield *num;
*num += 1; //~ERROR: dereferenced after this allocation got freed *num += 1; //~ERROR: has been freed
} }
} }

View file

@ -1,8 +1,8 @@
error: Undefined Behavior: pointer to ALLOC was dereferenced after this allocation got freed error: Undefined Behavior: dereferencing pointer failed: ALLOC has been freed, so this pointer is dangling
--> $DIR/generator-pinned-moved.rs:LL:CC --> $DIR/generator-pinned-moved.rs:LL:CC
| |
LL | *num += 1; LL | *num += 1;
| ^^^^^^^^^ pointer to ALLOC was dereferenced after this allocation got freed | ^^^^^^^^^ dereferencing pointer failed: ALLOC has been freed, so this pointer is dangling
| |
= help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = 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: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information

View file

@ -16,5 +16,5 @@ fn main() {
drop(strong); drop(strong);
// But not any more. We can do Weak::as_raw(&weak), but accessing the pointer would lead to // But not any more. We can do Weak::as_raw(&weak), but accessing the pointer would lead to
// undefined behaviour. // undefined behaviour.
assert_eq!(42, **unsafe { &*Weak::as_ptr(&weak) }); //~ ERROR: dereferenced after this allocation got freed assert_eq!(42, **unsafe { &*Weak::as_ptr(&weak) }); //~ ERROR: has been freed
} }

View file

@ -1,8 +1,8 @@
error: Undefined Behavior: pointer to ALLOC was dereferenced after this allocation got freed error: Undefined Behavior: dereferencing pointer failed: ALLOC has been freed, so this pointer is dangling
--> $DIR/rc_as_ptr.rs:LL:CC --> $DIR/rc_as_ptr.rs:LL:CC
| |
LL | assert_eq!(42, **unsafe { &*Weak::as_ptr(&weak) }); LL | assert_eq!(42, **unsafe { &*Weak::as_ptr(&weak) });
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ pointer to ALLOC was dereferenced after this allocation got freed | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ dereferencing pointer failed: ALLOC has been freed, so this pointer is dangling
| |
= help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = 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: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information

View file

@ -14,6 +14,6 @@ fn main() {
0, 0,
); );
libc::munmap(ptr, 4096); libc::munmap(ptr, 4096);
let _x = *(ptr as *mut u8); //~ ERROR: was dereferenced after this allocation got freed let _x = *(ptr as *mut u8); //~ ERROR: has been freed
} }
} }

View file

@ -13,11 +13,11 @@ LL | libc::munmap(ptr, 4096);
= note: BACKTRACE: = note: BACKTRACE:
= note: inside `main` at $DIR/mmap_use_after_munmap.rs:LL:CC = note: inside `main` at $DIR/mmap_use_after_munmap.rs:LL:CC
error: Undefined Behavior: pointer to ALLOC was dereferenced after this allocation got freed error: Undefined Behavior: dereferencing pointer failed: ALLOC has been freed, so this pointer is dangling
--> $DIR/mmap_use_after_munmap.rs:LL:CC --> $DIR/mmap_use_after_munmap.rs:LL:CC
| |
LL | let _x = *(ptr as *mut u8); LL | let _x = *(ptr as *mut u8);
| ^^^^^^^^^^^^^^^^^ pointer to ALLOC was dereferenced after this allocation got freed | ^^^^^^^^^^^^^^^^^ dereferencing pointer failed: ALLOC has been freed, so this pointer is dangling
| |
= help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = 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: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information

View file

@ -8,5 +8,5 @@ fn main() {
let mut x_box = Box::new(1u8); let mut x_box = Box::new(1u8);
let x = &mut *x_box as *mut _ as *mut [u8; 0]; let x = &mut *x_box as *mut _ as *mut [u8; 0];
drop(x_box); drop(x_box);
unsafe { *x = zst_val }; //~ ERROR: dereferenced after this allocation got freed unsafe { *x = zst_val }; //~ ERROR: has been freed
} }

View file

@ -1,8 +1,8 @@
error: Undefined Behavior: pointer to ALLOC was dereferenced after this allocation got freed error: Undefined Behavior: dereferencing pointer failed: ALLOC has been freed, so this pointer is dangling
--> $DIR/zst2.rs:LL:CC --> $DIR/zst2.rs:LL:CC
| |
LL | unsafe { *x = zst_val }; LL | unsafe { *x = zst_val };
| ^^^^^^^^^^^^ pointer to ALLOC was dereferenced after this allocation got freed | ^^^^^^^^^^^^ dereferencing pointer failed: ALLOC has been freed, so this pointer is dangling
| |
= help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = 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: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information

View file

@ -2,13 +2,13 @@ error[E0080]: evaluation of constant value failed
--> $DIR/dealloc_intrinsic_dangling.rs:10:5 --> $DIR/dealloc_intrinsic_dangling.rs:10:5
| |
LL | &*ptr LL | &*ptr
| ^^^^^ pointer to alloc2 was dereferenced after this allocation got freed | ^^^^^ dereferencing pointer failed: alloc2 has been freed, so this pointer is dangling
error[E0080]: evaluation of constant value failed error[E0080]: evaluation of constant value failed
--> $DIR/dealloc_intrinsic_dangling.rs:18:5 --> $DIR/dealloc_intrinsic_dangling.rs:18:5
| |
LL | *reference LL | *reference
| ^^^^^^^^^^ pointer to alloc4 was dereferenced after this allocation got freed | ^^^^^^^^^^ dereferencing pointer failed: alloc4 has been freed, so this pointer is dangling
error: aborting due to 2 previous errors error: aborting due to 2 previous errors

View file

@ -2,7 +2,7 @@ error[E0080]: evaluation of constant value failed
--> $DIR/dealloc_intrinsic_duplicate.rs:9:5 --> $DIR/dealloc_intrinsic_duplicate.rs:9:5
| |
LL | intrinsics::const_deallocate(ptr, 4, 4); LL | intrinsics::const_deallocate(ptr, 4, 4);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ pointer to alloc2 was dereferenced after this allocation got freed | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ memory access failed: alloc2 has been freed, so this pointer is dangling
error: aborting due to previous error error: aborting due to previous error

View file

@ -2,7 +2,7 @@ error[E0080]: evaluation of constant value failed
--> $DIR/issue-49296.rs:9:16 --> $DIR/issue-49296.rs:9:16
| |
LL | const X: u64 = *wat(42); LL | const X: u64 = *wat(42);
| ^^^^^^^^ pointer to alloc3 was dereferenced after this allocation got freed | ^^^^^^^^ dereferencing pointer failed: alloc3 has been freed, so this pointer is dangling
error: aborting due to previous error error: aborting due to previous error