Skip to content

Commit e5b7d00

Browse files
committed
miri/const eval: support MaybeDangling
1 parent 4efbe0c commit e5b7d00

9 files changed

Lines changed: 96 additions & 23 deletions

File tree

compiler/rustc_const_eval/src/interpret/validity.rs

Lines changed: 35 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
use std::borrow::Cow;
88
use std::fmt::Write;
99
use std::hash::Hash;
10+
use std::mem;
1011
use std::num::NonZero;
1112

1213
use either::{Left, Right};
@@ -288,6 +289,7 @@ struct ValidityVisitor<'rt, 'tcx, M: Machine<'tcx>> {
288289
/// If this is `Some`, then `reset_provenance_and_padding` must be true (but not vice versa:
289290
/// we might not track data vs padding bytes if the operand isn't stored in memory anyway).
290291
data_bytes: Option<RangeSet>,
292+
may_dangle: bool,
291293
}
292294

293295
impl<'rt, 'tcx, M: Machine<'tcx>> ValidityVisitor<'rt, 'tcx, M> {
@@ -503,27 +505,29 @@ impl<'rt, 'tcx, M: Machine<'tcx>> ValidityVisitor<'rt, 'tcx, M> {
503505
// alignment and size determined by the layout (size will be 0,
504506
// alignment should take attributes into account).
505507
.unwrap_or_else(|| (place.layout.size, place.layout.align.abi));
506-
// Direct call to `check_ptr_access_align` checks alignment even on CTFE machines.
507-
try_validation!(
508-
self.ecx.check_ptr_access(
509-
place.ptr(),
510-
size,
511-
CheckInAllocMsg::Dereferenceable, // will anyway be replaced by validity message
512-
),
513-
self.path,
514-
Ub(DanglingIntPointer { addr: 0, .. }) => NullPtr { ptr_kind, maybe: false },
515-
Ub(DanglingIntPointer { addr: i, .. }) => DanglingPtrNoProvenance {
516-
ptr_kind,
517-
// FIXME this says "null pointer" when null but we need translate
518-
pointer: format!("{}", Pointer::<Option<AllocId>>::without_provenance(i))
519-
},
520-
Ub(PointerOutOfBounds { .. }) => DanglingPtrOutOfBounds {
521-
ptr_kind
522-
},
523-
Ub(PointerUseAfterFree(..)) => DanglingPtrUseAfterFree {
524-
ptr_kind,
525-
},
526-
);
508+
if !self.may_dangle {
509+
// Direct call to `check_ptr_access_align` checks alignment even on CTFE machines.
510+
try_validation!(
511+
self.ecx.check_ptr_access(
512+
place.ptr(),
513+
size,
514+
CheckInAllocMsg::Dereferenceable, // will anyway be replaced by validity message
515+
),
516+
self.path,
517+
Ub(DanglingIntPointer { addr: 0, .. }) => NullPtr { ptr_kind, maybe: false },
518+
Ub(DanglingIntPointer { addr: i, .. }) => DanglingPtrNoProvenance {
519+
ptr_kind,
520+
// FIXME this says "null pointer" when null but we need translate
521+
pointer: format!("{}", Pointer::<Option<AllocId>>::without_provenance(i))
522+
},
523+
Ub(PointerOutOfBounds { .. }) => DanglingPtrOutOfBounds {
524+
ptr_kind
525+
},
526+
Ub(PointerUseAfterFree(..)) => DanglingPtrUseAfterFree {
527+
ptr_kind,
528+
},
529+
);
530+
}
527531
try_validation!(
528532
self.ecx.check_ptr_align(
529533
place.ptr(),
@@ -536,6 +540,7 @@ impl<'rt, 'tcx, M: Machine<'tcx>> ValidityVisitor<'rt, 'tcx, M> {
536540
found_bytes: has.bytes()
537541
},
538542
);
543+
539544
// Make sure this is non-null. We checked dereferenceability above, but if `size` is zero
540545
// that does not imply non-null.
541546
let scalar = Scalar::from_maybe_pointer(place.ptr(), self.ecx);
@@ -1265,6 +1270,14 @@ impl<'rt, 'tcx, M: Machine<'tcx>> ValueVisitor<'tcx, M> for ValidityVisitor<'rt,
12651270
ty::PatternKind::Or(_patterns) => {}
12661271
}
12671272
}
1273+
ty::Adt(adt, _) if adt.is_maybe_dangling() => {
1274+
let could_dangle = mem::replace(&mut self.may_dangle, true);
1275+
1276+
let inner = self.ecx.project_field(val, FieldIdx::ZERO)?;
1277+
self.visit_value(&inner)?;
1278+
1279+
self.may_dangle = could_dangle;
1280+
}
12681281
_ => {
12691282
// default handler
12701283
try_validation!(
@@ -1350,6 +1363,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
13501363
ecx,
13511364
reset_provenance_and_padding,
13521365
data_bytes: reset_padding.then_some(RangeSet(Vec::new())),
1366+
may_dangle: false,
13531367
};
13541368
v.visit_value(val)?;
13551369
v.reset_padding(val)?;

src/tools/miri/src/borrow_tracker/stacked_borrows/mod.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -917,6 +917,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
917917
RetagInfo { cause: self.retag_cause, in_field: self.in_field },
918918
)?;
919919
self.ecx.write_immediate(*val, place)?;
920+
920921
interp_ok(())
921922
}
922923
}
@@ -964,6 +965,9 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
964965
// even if field retagging is not enabled. *shrug*)
965966
self.walk_value(place)?;
966967
}
968+
ty::Adt(adt, _) if adt.is_maybe_dangling() => {
969+
// Skip traversing for everything inside of `MaybeDangling`
970+
}
967971
_ => {
968972
// Not a reference/pointer/box. Recurse.
969973
let in_field = mem::replace(&mut self.in_field, true); // remember and restore old value

src/tools/miri/src/borrow_tracker/tree_borrows/mod.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -523,6 +523,9 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
523523
// even if field retagging is not enabled. *shrug*)
524524
self.walk_value(place)?;
525525
}
526+
ty::Adt(adt, _) if adt.is_maybe_dangling() => {
527+
// Skip traversing for everything inside of `MaybeDangling`
528+
}
526529
_ => {
527530
// Not a reference/pointer/box. Recurse.
528531
self.walk_value(place)?;
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
#![feature(maybe_dangling)]
2+
use std::mem::{transmute, MaybeDangling};
3+
use std::ptr::null;
4+
5+
fn main() {
6+
unsafe { transmute::<MaybeDangling<*const u8>, MaybeDangling<&u8>>(MaybeDangling::new(null())) };
7+
//~^ ERROR: Undefined Behavior: constructing invalid value: encountered a null reference
8+
}
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
error: Undefined Behavior: constructing invalid value: encountered a null reference
2+
--> tests/fail/both_borrows/maybe_dangling_null.rs:LL:CC
3+
|
4+
LL | unsafe { transmute::<MaybeDangling<*const u8>, MaybeDangling<&u8>>(MaybeDangling::new(null())) };
5+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Undefined Behavior occurred here
6+
|
7+
= help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior
8+
= help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information
9+
10+
note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace
11+
12+
error: aborting due to 1 previous error
13+
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
#![feature(maybe_dangling)]
2+
use std::mem::{transmute, MaybeDangling};
3+
4+
fn main() {
5+
let a = [1u16, 0u16];
6+
unsafe { transmute::<MaybeDangling<*const u16>, MaybeDangling<&u16>>(MaybeDangling::new(a.as_ptr().byte_add(1))) };
7+
//~^ ERROR: Undefined Behavior: constructing invalid value: encountered an unaligned reference
8+
}
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
error: Undefined Behavior: constructing invalid value: encountered an unaligned reference (required ALIGN byte alignment but found ALIGN)
2+
--> tests/fail/both_borrows/maybe_dangling_unalighed.rs:LL:CC
3+
|
4+
LL | unsafe { transmute::<MaybeDangling<*const u16>, MaybeDangling<&u16>>(MaybeDangling::new(a.as_ptr().byte_add(1))) };
5+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Undefined Behavior occurred here
6+
|
7+
= help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior
8+
= help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information
9+
10+
note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace
11+
12+
error: aborting due to 1 previous error
13+
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
#![feature(maybe_dangling)]
2+
use std::mem::{self, MaybeDangling};
3+
use std::ptr::drop_in_place;
4+
5+
fn main() {
6+
let mut x = MaybeDangling::new(Box::new(1));
7+
unsafe { drop_in_place(x.as_mut()) };
8+
let x = x; // move
9+
mem::forget(x);
10+
}
Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
0..1: [ SharedReadWrite<TAG> ]
22
0..1: [ SharedReadWrite<TAG> ]
33
0..1: [ SharedReadWrite<TAG> ]
4-
0..1: [ SharedReadWrite<TAG> Unique<TAG> Unique<TAG> Unique<TAG> Unique<TAG> Unique<TAG> Unique<TAG> Unique<TAG> Unique<TAG> Unique<TAG> Unique<TAG> Unique<TAG> ]
5-
0..1: [ SharedReadWrite<TAG> Disabled<TAG> Disabled<TAG> Disabled<TAG> Disabled<TAG> Disabled<TAG> Disabled<TAG> Disabled<TAG> Disabled<TAG> Disabled<TAG> Disabled<TAG> Disabled<TAG> SharedReadOnly<TAG> ]
4+
0..1: [ SharedReadWrite<TAG> Unique<TAG> Unique<TAG> Unique<TAG> Unique<TAG> Unique<TAG> Unique<TAG> Unique<TAG> ]
5+
0..1: [ SharedReadWrite<TAG> Disabled<TAG> Disabled<TAG> Disabled<TAG> Disabled<TAG> Disabled<TAG> Disabled<TAG> Disabled<TAG> SharedReadOnly<TAG> ]
66
0..1: [ unknown-bottom(..<TAG>) ]

0 commit comments

Comments
 (0)