Skip to content

Commit c48445e

Browse files
committed
Auto merge of #114330 - RalfJung:dagling-ptr-deref, r=oli-obk
don't UB on dangling ptr deref, instead check inbounds on projections This implements rust-lang/reference#1387 in Miri. See that PR for what the change is about. Detecting dangling references in `let x = &...;` is now done by validity checking only, so some tests need to have validity checking enabled. There is no longer inherently a "nodangle" check in evaluating the expression `&*ptr` (aside from the aliasing model). r? `@oli-obk` Based on: - rust-lang/reference#1387 - rust-lang/rust#115524
2 parents e35c181 + dd7e34c commit c48445e

File tree

92 files changed

+380
-295
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

92 files changed

+380
-295
lines changed

src/borrow_tracker/stacked_borrows/mod.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ use log::trace;
1414
use rustc_data_structures::fx::FxHashSet;
1515
use rustc_middle::mir::{Mutability, RetagKind};
1616
use rustc_middle::ty::{self, layout::HasParamEnv, Ty};
17-
use rustc_target::abi::{Abi, Align, Size};
17+
use rustc_target::abi::{Abi, Size};
1818

1919
use crate::borrow_tracker::{
2020
stacked_borrows::diagnostics::{AllocHistory, DiagnosticCx, DiagnosticCxBuilder},
@@ -616,7 +616,7 @@ trait EvalContextPrivExt<'mir: 'ecx, 'tcx: 'mir, 'ecx>: crate::MiriInterpCxExt<'
616616
) -> InterpResult<'tcx, Option<Provenance>> {
617617
let this = self.eval_context_mut();
618618
// Ensure we bail out if the pointer goes out-of-bounds (see miri#1050).
619-
this.check_ptr_access_align(place.ptr(), size, Align::ONE, CheckInAllocMsg::InboundsTest)?;
619+
this.check_ptr_access(place.ptr(), size, CheckInAllocMsg::InboundsTest)?;
620620

621621
// It is crucial that this gets called on all code paths, to ensure we track tag creation.
622622
let log_creation = |this: &MiriInterpCx<'mir, 'tcx>,

src/borrow_tracker/tree_borrows/mod.rs

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
use log::trace;
22

3-
use rustc_target::abi::{Abi, Align, Size};
3+
use rustc_target::abi::{Abi, Size};
44

55
use crate::borrow_tracker::{
66
AccessKind, GlobalState, GlobalStateInner, ProtectorKind, RetagFields,
@@ -206,10 +206,9 @@ trait EvalContextPrivExt<'mir: 'ecx, 'tcx: 'mir, 'ecx>: crate::MiriInterpCxExt<'
206206
// Make sure the new permission makes sense as the initial permission of a fresh tag.
207207
assert!(new_perm.initial_state.is_initial());
208208
// Ensure we bail out if the pointer goes out-of-bounds (see miri#1050).
209-
this.check_ptr_access_align(
209+
this.check_ptr_access(
210210
place.ptr(),
211211
ptr_size,
212-
Align::ONE,
213212
CheckInAllocMsg::InboundsTest,
214213
)?;
215214

src/concurrency/data_race.rs

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1017,11 +1017,9 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: MiriInterpCxExt<'mir, 'tcx> {
10171017
// even if the type they wrap would be less aligned (e.g. AtomicU64 on 32bit must
10181018
// be 8-aligned).
10191019
let align = Align::from_bytes(place.layout.size.bytes()).unwrap();
1020-
this.check_ptr_access_align(
1020+
this.check_ptr_align(
10211021
place.ptr(),
1022-
place.layout.size,
10231022
align,
1024-
CheckInAllocMsg::MemoryAccessTest,
10251023
)?;
10261024
// Ensure the allocation is mutable. Even failing (read-only) compare_exchange need mutable
10271025
// memory on many targets (i.e., they segfault if taht memory is mapped read-only), and

src/helpers.rs

Lines changed: 6 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -697,27 +697,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
697697
) -> InterpResult<'tcx, MPlaceTy<'tcx, Provenance>> {
698698
let this = self.eval_context_ref();
699699
let ptr = this.read_pointer(op)?;
700-
701-
let mplace = MPlaceTy::from_aligned_ptr(ptr, layout);
702-
703-
this.check_mplace(&mplace)?;
704-
705-
Ok(mplace)
706-
}
707-
708-
/// Deref' a pointer *without* checking that the place is dereferenceable.
709-
fn deref_pointer_unchecked(
710-
&self,
711-
val: &ImmTy<'tcx, Provenance>,
712-
layout: TyAndLayout<'tcx>,
713-
) -> InterpResult<'tcx, MPlaceTy<'tcx, Provenance>> {
714-
let this = self.eval_context_ref();
715-
let mut mplace = this.ref_to_mplace(val)?;
716-
717-
mplace.layout = layout;
718-
mplace.align = layout.align.abi;
719-
720-
Ok(mplace)
700+
Ok(this.ptr_to_mplace(ptr, layout))
721701
}
722702

723703
/// Calculates the MPlaceTy given the offset and layout of an access on an operand
@@ -805,7 +785,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
805785
loop {
806786
// FIXME: We are re-getting the allocation each time around the loop.
807787
// Would be nice if we could somehow "extend" an existing AllocRange.
808-
let alloc = this.get_ptr_alloc(ptr.offset(len, this)?, size1, Align::ONE)?.unwrap(); // not a ZST, so we will get a result
788+
let alloc = this.get_ptr_alloc(ptr.offset(len, this)?, size1)?.unwrap(); // not a ZST, so we will get a result
809789
let byte = alloc.read_integer(alloc_range(Size::ZERO, size1))?.to_u8()?;
810790
if byte == 0 {
811791
break;
@@ -845,13 +825,13 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
845825
fn read_wide_str(&self, mut ptr: Pointer<Option<Provenance>>) -> InterpResult<'tcx, Vec<u16>> {
846826
let this = self.eval_context_ref();
847827
let size2 = Size::from_bytes(2);
848-
let align2 = Align::from_bytes(2).unwrap();
828+
this.check_ptr_align(ptr, Align::from_bytes(2).unwrap())?;
849829

850830
let mut wchars = Vec::new();
851831
loop {
852832
// FIXME: We are re-getting the allocation each time around the loop.
853833
// Would be nice if we could somehow "extend" an existing AllocRange.
854-
let alloc = this.get_ptr_alloc(ptr, size2, align2)?.unwrap(); // not a ZST, so we will get a result
834+
let alloc = this.get_ptr_alloc(ptr, size2)?.unwrap(); // not a ZST, so we will get a result
855835
let wchar = alloc.read_integer(alloc_range(Size::ZERO, size2))?.to_u16()?;
856836
if wchar == 0 {
857837
break;
@@ -887,8 +867,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
887867
// Store the UTF-16 string.
888868
let size2 = Size::from_bytes(2);
889869
let this = self.eval_context_mut();
870+
this.check_ptr_align(ptr, Align::from_bytes(2).unwrap())?;
890871
let mut alloc = this
891-
.get_ptr_alloc_mut(ptr, size2 * string_length, Align::from_bytes(2).unwrap())?
872+
.get_ptr_alloc_mut(ptr, size2 * string_length)?
892873
.unwrap(); // not a ZST, so we will get a result
893874
for (offset, wchar) in wide_str.iter().copied().chain(iter::once(0x0000)).enumerate() {
894875
let offset = u64::try_from(offset).unwrap();

src/machine.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1285,6 +1285,7 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for MiriMachine<'mir, 'tcx> {
12851285
// We do need to write `uninit` so that even after the call ends, the former contents of
12861286
// this place cannot be observed any more. We do the write after retagging so that for
12871287
// Tree Borrows, this is considered to activate the new tag.
1288+
// Conveniently this also ensures that the place actually points to suitable memory.
12881289
ecx.write_uninit(&protected_place)?;
12891290
// Now we throw away the protected place, ensuring its tag is never used again.
12901291
Ok(())

src/shims/foreign_items.rs

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -807,9 +807,7 @@ trait EvalContextExtPriv<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
807807

808808
this.mem_copy(
809809
ptr_src,
810-
Align::ONE,
811810
ptr_dest,
812-
Align::ONE,
813811
Size::from_bytes(n),
814812
true,
815813
)?;
@@ -830,9 +828,7 @@ trait EvalContextExtPriv<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
830828
let n = this.read_c_str(ptr_src)?.len().checked_add(1).unwrap();
831829
this.mem_copy(
832830
ptr_src,
833-
Align::ONE,
834831
ptr_dest,
835-
Align::ONE,
836832
Size::from_bytes(n),
837833
true,
838834
)?;

src/shims/unix/fs.rs

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ use log::trace;
1313

1414
use rustc_data_structures::fx::FxHashMap;
1515
use rustc_middle::ty::TyCtxt;
16-
use rustc_target::abi::{Align, Size};
16+
use rustc_target::abi::Size;
1717

1818
use crate::shims::os_str::bytes_to_os_str;
1919
use crate::*;
@@ -756,10 +756,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
756756
trace!("Reading from FD {}, size {}", fd, count);
757757

758758
// Check that the *entire* buffer is actually valid memory.
759-
this.check_ptr_access_align(
759+
this.check_ptr_access(
760760
buf,
761761
Size::from_bytes(count),
762-
Align::ONE,
763762
CheckInAllocMsg::MemoryAccessTest,
764763
)?;
765764

@@ -810,10 +809,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
810809
// Isolation check is done via `FileDescriptor` trait.
811810

812811
// Check that the *entire* buffer is actually valid memory.
813-
this.check_ptr_access_align(
812+
this.check_ptr_access(
814813
buf,
815814
Size::from_bytes(count),
816-
Align::ONE,
817815
CheckInAllocMsg::MemoryAccessTest,
818816
)?;
819817

@@ -1370,7 +1368,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
13701368
("d_reclen", size.into()),
13711369
("d_type", file_type.into()),
13721370
],
1373-
&MPlaceTy::from_aligned_ptr(entry, dirent64_layout),
1371+
&this.ptr_to_mplace(entry, dirent64_layout),
13741372
)?;
13751373

13761374
let name_ptr = entry.offset(Size::from_bytes(d_name_offset), this)?;

src/shims/unix/linux/sync.rs

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ pub fn futex<'tcx>(
3434

3535
let thread = this.get_active_thread();
3636
// This is a vararg function so we have to bring our own type for this pointer.
37-
let addr = MPlaceTy::from_aligned_ptr(addr, this.machine.layouts.i32);
37+
let addr = this.ptr_to_mplace(addr, this.machine.layouts.i32);
3838
let addr_usize = addr.ptr().addr().bytes();
3939

4040
let futex_private = this.eval_libc_i32("FUTEX_PRIVATE_FLAG");
@@ -85,9 +85,8 @@ pub fn futex<'tcx>(
8585
return Ok(());
8686
}
8787

88-
// `read_timespec` will check the place when it is not null.
89-
let timeout = this.deref_pointer_unchecked(
90-
&this.read_immediate(&args[3])?,
88+
let timeout = this.deref_pointer_as(
89+
&args[3],
9190
this.libc_ty_layout("timespec"),
9291
)?;
9392
let timeout_time = if this.ptr_is_null(timeout.ptr())? {

src/shims/windows/sync.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -322,8 +322,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
322322

323323
let layout = this.machine.layouts.uint(size).unwrap();
324324
let futex_val = this
325-
.read_scalar_atomic(&MPlaceTy::from_aligned_ptr(ptr, layout), AtomicReadOrd::Relaxed)?;
326-
let compare_val = this.read_scalar(&MPlaceTy::from_aligned_ptr(compare, layout))?;
325+
.read_scalar_atomic(&this.ptr_to_mplace(ptr, layout), AtomicReadOrd::Relaxed)?;
326+
let compare_val = this.read_scalar(&this.ptr_to_mplace(compare, layout))?;
327327

328328
if futex_val == compare_val {
329329
// If the values are the same, we have to block.

src/shims/x86/sse3.rs

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
use rustc_middle::mir;
22
use rustc_span::Symbol;
3-
use rustc_target::abi::Align;
43
use rustc_target::spec::abi::Abi;
54

65
use super::horizontal_bin_op;
@@ -76,9 +75,7 @@ pub(super) trait EvalContextExt<'mir, 'tcx: 'mir>:
7675

7776
this.mem_copy(
7877
src_ptr,
79-
Align::ONE,
8078
dest.ptr(),
81-
Align::ONE,
8279
dest.layout.size,
8380
/*nonoverlapping*/ true,
8481
)?;

0 commit comments

Comments
 (0)