Skip to content

Commit c428102

Browse files
committed
miri: support MaybeDangling
1 parent 29aa44b commit c428102

File tree

3 files changed

+62
-29
lines changed

3 files changed

+62
-29
lines changed

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);
@@ -1269,6 +1274,14 @@ impl<'rt, 'tcx, M: Machine<'tcx>> ValueVisitor<'tcx, M> for ValidityVisitor<'rt,
12691274
ty::PatternKind::Or(_patterns) => {}
12701275
}
12711276
}
1277+
ty::Adt(adt, _) if adt.is_maybe_dangling() => {
1278+
let could_dangle = mem::replace(&mut self.may_dangle, true);
1279+
1280+
let inner = self.ecx.project_field(val, FieldIdx::ZERO)?;
1281+
self.visit_value(&inner)?;
1282+
1283+
self.may_dangle = could_dangle;
1284+
}
12721285
_ => {
12731286
// default handler
12741287
try_validation!(
@@ -1354,6 +1367,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
13541367
ecx,
13551368
reset_provenance_and_padding,
13561369
data_bytes: reset_padding.then_some(RangeSet(Vec::new())),
1370+
may_dangle: false,
13571371
};
13581372
v.visit_value(val)?;
13591373
v.reset_padding(val)?;

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

Lines changed: 20 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -892,7 +892,8 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
892892
RetagKind::FnEntry => RetagCause::FnEntry,
893893
RetagKind::Default | RetagKind::Raw => RetagCause::Normal,
894894
};
895-
let mut visitor = RetagVisitor { ecx: this, kind, retag_cause, in_field: false };
895+
let mut visitor =
896+
RetagVisitor { ecx: this, kind, retag_cause, in_field: false, may_dangle: false };
896897
return visitor.visit_value(place);
897898

898899
// The actual visitor.
@@ -901,6 +902,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
901902
kind: RetagKind,
902903
retag_cause: RetagCause,
903904
in_field: bool,
905+
may_dangle: bool,
904906
}
905907
impl<'ecx, 'tcx> RetagVisitor<'ecx, 'tcx> {
906908
#[inline(always)] // yes this helps in our benchmarks
@@ -909,13 +911,16 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
909911
place: &PlaceTy<'tcx>,
910912
new_perm: NewPermission,
911913
) -> InterpResult<'tcx> {
912-
let val = self.ecx.read_immediate(&self.ecx.place_to_op(place)?)?;
913-
let val = self.ecx.sb_retag_reference(
914-
&val,
915-
new_perm,
916-
RetagInfo { cause: self.retag_cause, in_field: self.in_field },
917-
)?;
918-
self.ecx.write_immediate(*val, place)?;
914+
if !self.may_dangle {
915+
let val = self.ecx.read_immediate(&self.ecx.place_to_op(place)?)?;
916+
let val = self.ecx.sb_retag_reference(
917+
&val,
918+
new_perm,
919+
RetagInfo { cause: self.retag_cause, in_field: self.in_field },
920+
)?;
921+
self.ecx.write_immediate(*val, place)?;
922+
}
923+
919924
interp_ok(())
920925
}
921926
}
@@ -963,6 +968,13 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
963968
// even if field retagging is not enabled. *shrug*)
964969
self.walk_value(place)?;
965970
}
971+
ty::Adt(adt, _) if adt.is_maybe_dangling() => {
972+
let in_field = mem::replace(&mut self.in_field, true); // remember and restore old value
973+
let may_dangle = mem::replace(&mut self.may_dangle, true); // remember and restore old value
974+
self.walk_value(place)?;
975+
self.may_dangle = may_dangle;
976+
self.in_field = in_field;
977+
}
966978
_ => {
967979
// Not a reference/pointer/box. Recurse.
968980
let in_field = mem::replace(&mut self.in_field, true); // remember and restore old value
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
use std::mem::ManuallyDrop;
2+
3+
fn main() {
4+
let mut x = ManuallyDrop::new(Box::new(1));
5+
unsafe { ManuallyDrop::drop(&mut x) };
6+
let _x = x; // move
7+
}

0 commit comments

Comments
 (0)