Skip to content

Commit 4fbe434

Browse files
committed
Poison any MemPlace created from a zst Operand (or otherwise via MPlaceTy::dangling) so you can't get the address back out.
1 parent cac6f4c commit 4fbe434

File tree

6 files changed

+102
-43
lines changed

6 files changed

+102
-43
lines changed

src/librustc_mir/interpret/eval_context.rs

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ use rustc_macros::HashStable;
2020
use rustc_span::source_map::{self, Span, DUMMY_SP};
2121

2222
use super::{
23-
Immediate, MPlaceTy, Machine, MemPlace, Memory, OpTy, Operand, Place, PlaceTy,
23+
Immediate, MPlaceTy, Machine, MemPlace, MemPlaceMeta, Memory, OpTy, Operand, Place, PlaceTy,
2424
ScalarMaybeUndef, StackPopInfo,
2525
};
2626

@@ -393,7 +393,7 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
393393
/// This can fail to provide an answer for extern types.
394394
pub(super) fn size_and_align_of(
395395
&self,
396-
metadata: Option<Scalar<M::PointerTag>>,
396+
metadata: MemPlaceMeta<M::PointerTag>,
397397
layout: TyLayout<'tcx>,
398398
) -> InterpResult<'tcx, Option<(Size, Align)>> {
399399
if !layout.is_unsized() {
@@ -465,14 +465,13 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
465465
Ok(Some((size, align)))
466466
}
467467
ty::Dynamic(..) => {
468-
let vtable = metadata.expect("dyn trait fat ptr must have vtable");
468+
let vtable = metadata.unwrap_unsized();
469469
// Read size and align from vtable (already checks size).
470470
Ok(Some(self.read_size_and_align_from_vtable(vtable)?))
471471
}
472472

473473
ty::Slice(_) | ty::Str => {
474-
let len =
475-
metadata.expect("slice fat ptr must have length").to_machine_usize(self)?;
474+
let len = metadata.unwrap_unsized().to_machine_usize(self)?;
476475
let elem = layout.field(self, 0)?;
477476

478477
// Make sure the slice is not too big.
@@ -818,8 +817,8 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
818817
" by align({}){} ref:",
819818
mplace.align.bytes(),
820819
match mplace.meta {
821-
Some(meta) => format!(" meta({:?})", meta),
822-
None => String::new(),
820+
MemPlaceMeta::Unsized(meta) => format!(" meta({:?})", meta),
821+
MemPlaceMeta::Poison | MemPlaceMeta::None => String::new(),
823822
}
824823
)
825824
.unwrap();

src/librustc_mir/interpret/intern.rs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -193,7 +193,7 @@ impl<'rt, 'mir, 'tcx, M: CompileTimeMachine<'mir, 'tcx>> ValueVisitor<'mir, 'tcx
193193
{
194194
// Validation has already errored on an invalid vtable pointer so we can safely not
195195
// do anything if this is not a real pointer.
196-
if let Scalar::Ptr(vtable) = mplace.meta.unwrap() {
196+
if let Scalar::Ptr(vtable) = mplace.meta.unwrap_unsized() {
197197
// Explicitly choose `Immutable` here, since vtables are immutable, even
198198
// if the reference of the fat pointer is mutable.
199199
self.intern_shallow(vtable.alloc_id, Mutability::Not, None)?;
@@ -226,7 +226,8 @@ impl<'rt, 'mir, 'tcx, M: CompileTimeMachine<'mir, 'tcx>> ValueVisitor<'mir, 'tcx
226226
| (InternMode::Const, hir::Mutability::Mut) => match referenced_ty.kind {
227227
ty::Array(_, n)
228228
if n.eval_usize(self.ecx.tcx.tcx, self.ecx.param_env) == 0 => {}
229-
ty::Slice(_) if mplace.meta.unwrap().to_machine_usize(self.ecx)? == 0 => {}
229+
ty::Slice(_)
230+
if mplace.meta.unwrap_unsized().to_machine_usize(self.ecx)? == 0 => {}
230231
_ => bug!("const qualif failed to prevent mutable references"),
231232
},
232233
}

src/librustc_mir/interpret/mod.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ pub use rustc::mir::interpret::*; // have all the `interpret` symbols in one pla
2020

2121
pub use self::eval_context::{Frame, InterpCx, LocalState, LocalValue, StackPopCleanup};
2222

23-
pub use self::place::{MPlaceTy, MemPlace, Place, PlaceTy};
23+
pub use self::place::{MPlaceTy, MemPlace, MemPlaceMeta, Place, PlaceTy};
2424

2525
pub use self::memory::{AllocCheck, FnVal, Memory, MemoryKind};
2626

src/librustc_mir/interpret/place.rs

Lines changed: 72 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,45 @@ use super::{
2020
RawConst, Scalar, ScalarMaybeUndef,
2121
};
2222

23+
#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq, HashStable)]
24+
pub enum MemPlaceMeta<Tag = (), Id = AllocId> {
25+
Unsized(Scalar<Tag, Id>),
26+
/// `Sized` types or unsized `extern type`
27+
None,
28+
/// The address of this place may not be taken. This protects the `MemPlace` from coming from
29+
/// a ZST Operand with a backing allocation and being converted to an integer address. This
30+
/// should be impossible, because you can't take the address of an operand, but this is a second
31+
/// protection layer ensuring that we don't mess up.
32+
Poison,
33+
}
34+
35+
impl<Tag, Id> MemPlaceMeta<Tag, Id> {
36+
pub fn unwrap_unsized(self) -> Scalar<Tag, Id> {
37+
match self {
38+
Self::Unsized(s) => s,
39+
Self::None | Self::Poison => {
40+
bug!("expected wide pointer extra data (e.g. slice length or trait object vtable)")
41+
}
42+
}
43+
}
44+
fn is_unsized(self) -> bool {
45+
match self {
46+
Self::Unsized(_) => true,
47+
Self::None | Self::Poison => false,
48+
}
49+
}
50+
}
51+
52+
impl<Tag> MemPlaceMeta<Tag> {
53+
pub fn erase_tag(self) -> MemPlaceMeta<()> {
54+
match self {
55+
Self::Unsized(s) => MemPlaceMeta::Unsized(s.erase_tag()),
56+
Self::None => MemPlaceMeta::None,
57+
Self::Poison => MemPlaceMeta::Poison,
58+
}
59+
}
60+
}
61+
2362
#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq, HashStable)]
2463
pub struct MemPlace<Tag = (), Id = AllocId> {
2564
/// A place may have an integral pointer for ZSTs, and since it might
@@ -30,7 +69,7 @@ pub struct MemPlace<Tag = (), Id = AllocId> {
3069
/// Metadata for unsized places. Interpretation is up to the type.
3170
/// Must not be present for sized types, but can be missing for unsized types
3271
/// (e.g., `extern type`).
33-
pub meta: Option<Scalar<Tag, Id>>,
72+
pub meta: MemPlaceMeta<Tag, Id>,
3473
}
3574

3675
#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq, HashStable)]
@@ -88,16 +127,12 @@ impl<Tag> MemPlace<Tag> {
88127

89128
#[inline]
90129
pub fn erase_tag(self) -> MemPlace {
91-
MemPlace {
92-
ptr: self.ptr.erase_tag(),
93-
align: self.align,
94-
meta: self.meta.map(Scalar::erase_tag),
95-
}
130+
MemPlace { ptr: self.ptr.erase_tag(), align: self.align, meta: self.meta.erase_tag() }
96131
}
97132

98133
#[inline(always)]
99134
pub fn from_scalar_ptr(ptr: Scalar<Tag>, align: Align) -> Self {
100-
MemPlace { ptr, align, meta: None }
135+
MemPlace { ptr, align, meta: MemPlaceMeta::None }
101136
}
102137

103138
/// Produces a Place that will error if attempted to be read from or written to
@@ -116,15 +151,19 @@ impl<Tag> MemPlace<Tag> {
116151
#[inline(always)]
117152
pub fn to_ref(self) -> Immediate<Tag> {
118153
match self.meta {
119-
None => Immediate::Scalar(self.ptr.into()),
120-
Some(meta) => Immediate::ScalarPair(self.ptr.into(), meta.into()),
154+
MemPlaceMeta::None => Immediate::Scalar(self.ptr.into()),
155+
MemPlaceMeta::Unsized(meta) => Immediate::ScalarPair(self.ptr.into(), meta.into()),
156+
MemPlaceMeta::Poison => bug!(
157+
"MPlaceTy::dangling may never be used to produce a \
158+
place that will have the address of its pointee taken"
159+
),
121160
}
122161
}
123162

124163
pub fn offset(
125164
self,
126165
offset: Size,
127-
meta: Option<Scalar<Tag>>,
166+
meta: MemPlaceMeta<Tag>,
128167
cx: &impl HasDataLayout,
129168
) -> InterpResult<'tcx, Self> {
130169
Ok(MemPlace {
@@ -158,7 +197,7 @@ impl<'tcx, Tag> MPlaceTy<'tcx, Tag> {
158197
pub fn offset(
159198
self,
160199
offset: Size,
161-
meta: Option<Scalar<Tag>>,
200+
meta: MemPlaceMeta<Tag>,
162201
layout: TyLayout<'tcx>,
163202
cx: &impl HasDataLayout,
164203
) -> InterpResult<'tcx, Self> {
@@ -175,7 +214,9 @@ impl<'tcx, Tag> MPlaceTy<'tcx, Tag> {
175214
if self.layout.is_unsized() {
176215
// We need to consult `meta` metadata
177216
match self.layout.ty.kind {
178-
ty::Slice(..) | ty::Str => return self.mplace.meta.unwrap().to_machine_usize(cx),
217+
ty::Slice(..) | ty::Str => {
218+
return self.mplace.meta.unwrap_unsized().to_machine_usize(cx);
219+
}
179220
_ => bug!("len not supported on unsized type {:?}", self.layout.ty),
180221
}
181222
} else {
@@ -191,7 +232,7 @@ impl<'tcx, Tag> MPlaceTy<'tcx, Tag> {
191232
#[inline]
192233
pub(super) fn vtable(self) -> Scalar<Tag> {
193234
match self.layout.ty.kind {
194-
ty::Dynamic(..) => self.mplace.meta.unwrap(),
235+
ty::Dynamic(..) => self.mplace.meta.unwrap_unsized(),
195236
_ => bug!("vtable not supported on type {:?}", self.layout.ty),
196237
}
197238
}
@@ -276,8 +317,10 @@ where
276317
val.layout.ty.builtin_deref(true).expect("`ref_to_mplace` called on non-ptr type").ty;
277318
let layout = self.layout_of(pointee_type)?;
278319
let (ptr, meta) = match *val {
279-
Immediate::Scalar(ptr) => (ptr.not_undef()?, None),
280-
Immediate::ScalarPair(ptr, meta) => (ptr.not_undef()?, Some(meta.not_undef()?)),
320+
Immediate::Scalar(ptr) => (ptr.not_undef()?, MemPlaceMeta::None),
321+
Immediate::ScalarPair(ptr, meta) => {
322+
(ptr.not_undef()?, MemPlaceMeta::Unsized(meta.not_undef()?))
323+
}
281324
};
282325

283326
let mplace = MemPlace {
@@ -318,7 +361,7 @@ where
318361
) -> InterpResult<'tcx, Option<Pointer<M::PointerTag>>> {
319362
let size = size.unwrap_or_else(|| {
320363
assert!(!place.layout.is_unsized());
321-
assert!(place.meta.is_none());
364+
assert!(!place.meta.is_unsized());
322365
place.layout.size
323366
});
324367
self.memory.check_ptr_access(place.ptr, size, place.align)
@@ -411,7 +454,7 @@ where
411454
} else {
412455
// base.meta could be present; we might be accessing a sized field of an unsized
413456
// struct.
414-
(None, offset)
457+
(MemPlaceMeta::None, offset)
415458
};
416459

417460
// We do not look at `base.layout.align` nor `field_layout.align`, unlike
@@ -433,7 +476,7 @@ where
433476
};
434477
let layout = base.layout.field(self, 0)?;
435478
let dl = &self.tcx.data_layout;
436-
Ok((0..len).map(move |i| base.offset(i * stride, None, layout, dl)))
479+
Ok((0..len).map(move |i| base.offset(i * stride, MemPlaceMeta::None, layout, dl)))
437480
}
438481

439482
fn mplace_subslice(
@@ -466,10 +509,10 @@ where
466509
let (meta, ty) = match base.layout.ty.kind {
467510
// It is not nice to match on the type, but that seems to be the only way to
468511
// implement this.
469-
ty::Array(inner, _) => (None, self.tcx.mk_array(inner, inner_len)),
512+
ty::Array(inner, _) => (MemPlaceMeta::None, self.tcx.mk_array(inner, inner_len)),
470513
ty::Slice(..) => {
471514
let len = Scalar::from_uint(inner_len, self.pointer_size());
472-
(Some(len), base.layout.ty)
515+
(MemPlaceMeta::Unsized(len), base.layout.ty)
473516
}
474517
_ => bug!("cannot subslice non-array type: `{:?}`", base.layout.ty),
475518
};
@@ -483,7 +526,7 @@ where
483526
variant: VariantIdx,
484527
) -> InterpResult<'tcx, MPlaceTy<'tcx, M::PointerTag>> {
485528
// Downcasts only change the layout
486-
assert!(base.meta.is_none());
529+
assert!(!base.meta.is_unsized());
487530
Ok(MPlaceTy { layout: base.layout.for_variant(self, variant), ..base })
488531
}
489532

@@ -977,7 +1020,7 @@ where
9771020
pub fn force_allocation_maybe_sized(
9781021
&mut self,
9791022
place: PlaceTy<'tcx, M::PointerTag>,
980-
meta: Option<Scalar<M::PointerTag>>,
1023+
meta: MemPlaceMeta<M::PointerTag>,
9811024
) -> InterpResult<'tcx, (MPlaceTy<'tcx, M::PointerTag>, Option<Size>)> {
9821025
let (mplace, size) = match place.place {
9831026
Place::Local { frame, local } => {
@@ -1022,7 +1065,7 @@ where
10221065
&mut self,
10231066
place: PlaceTy<'tcx, M::PointerTag>,
10241067
) -> InterpResult<'tcx, MPlaceTy<'tcx, M::PointerTag>> {
1025-
Ok(self.force_allocation_maybe_sized(place, None)?.0)
1068+
Ok(self.force_allocation_maybe_sized(place, MemPlaceMeta::None)?.0)
10261069
}
10271070

10281071
pub fn allocate(
@@ -1042,8 +1085,11 @@ where
10421085
) -> MPlaceTy<'tcx, M::PointerTag> {
10431086
let ptr = self.memory.allocate_static_bytes(str.as_bytes(), kind);
10441087
let meta = Scalar::from_uint(str.len() as u128, self.pointer_size());
1045-
let mplace =
1046-
MemPlace { ptr: ptr.into(), align: Align::from_bytes(1).unwrap(), meta: Some(meta) };
1088+
let mplace = MemPlace {
1089+
ptr: ptr.into(),
1090+
align: Align::from_bytes(1).unwrap(),
1091+
meta: MemPlaceMeta::Unsized(meta),
1092+
};
10471093

10481094
let layout = self.layout_of(self.tcx.mk_static_str()).unwrap();
10491095
MPlaceTy { mplace, layout }
@@ -1151,7 +1197,7 @@ where
11511197
assert_eq!(align, layout.align.abi);
11521198
}
11531199

1154-
let mplace = MPlaceTy { mplace: MemPlace { meta: None, ..*mplace }, layout };
1200+
let mplace = MPlaceTy { mplace: MemPlace { meta: MemPlaceMeta::None, ..*mplace }, layout };
11551201
Ok((instance, mplace))
11561202
}
11571203
}

src/librustc_mir/interpret/snapshot.rs

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,9 @@ use rustc_span::source_map::Span;
2323
use syntax::ast::Mutability;
2424

2525
use super::eval_context::{LocalState, StackPopCleanup};
26-
use super::{Frame, Immediate, LocalValue, MemPlace, Memory, Operand, Place, ScalarMaybeUndef};
26+
use super::{
27+
Frame, Immediate, LocalValue, MemPlace, MemPlaceMeta, Memory, Operand, Place, ScalarMaybeUndef,
28+
};
2729
use crate::const_eval::CompileTimeInterpreter;
2830

2931
#[derive(Default)]
@@ -205,6 +207,14 @@ impl_snapshot_for!(
205207
}
206208
);
207209

210+
impl_snapshot_for!(
211+
enum MemPlaceMeta {
212+
Unsized(s),
213+
None,
214+
Poison,
215+
}
216+
);
217+
208218
impl_snapshot_for!(struct MemPlace {
209219
ptr,
210220
meta,

src/librustc_mir/interpret/validity.rs

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ use rustc_span::symbol::{sym, Symbol};
1616
use std::hash::Hash;
1717

1818
use super::{
19-
CheckInAllocMsg, GlobalAlloc, InterpCx, InterpResult, MPlaceTy, Machine, OpTy, Scalar,
19+
CheckInAllocMsg, GlobalAlloc, InterpCx, InterpResult, MPlaceTy, Machine, MemPlaceMeta, OpTy,
2020
ValueVisitor,
2121
};
2222

@@ -246,13 +246,13 @@ impl<'rt, 'mir, 'tcx, M: Machine<'mir, 'tcx>> ValidityVisitor<'rt, 'mir, 'tcx, M
246246

247247
fn check_wide_ptr_meta(
248248
&mut self,
249-
meta: Option<Scalar<M::PointerTag>>,
249+
meta: MemPlaceMeta<M::PointerTag>,
250250
pointee: TyLayout<'tcx>,
251251
) -> InterpResult<'tcx> {
252252
let tail = self.ecx.tcx.struct_tail_erasing_lifetimes(pointee.ty, self.ecx.param_env);
253253
match tail.kind {
254254
ty::Dynamic(..) => {
255-
let vtable = meta.unwrap();
255+
let vtable = meta.unwrap_unsized();
256256
try_validation!(
257257
self.ecx.memory.check_ptr_access(
258258
vtable,
@@ -276,7 +276,7 @@ impl<'rt, 'mir, 'tcx, M: Machine<'mir, 'tcx>> ValidityVisitor<'rt, 'mir, 'tcx, M
276276
}
277277
ty::Slice(..) | ty::Str => {
278278
let _len = try_validation!(
279-
meta.unwrap().to_machine_usize(self.ecx),
279+
meta.unwrap_unsized().to_machine_usize(self.ecx),
280280
"non-integer slice length in wide pointer",
281281
self.path
282282
);
@@ -572,8 +572,11 @@ impl<'rt, 'mir, 'tcx, M: Machine<'mir, 'tcx>> ValueVisitor<'mir, 'tcx, M>
572572
match op.layout.ty.kind {
573573
ty::Str => {
574574
let mplace = op.assert_mem_place(self.ecx); // strings are never immediate
575-
try_validation!(self.ecx.read_str(mplace),
576-
"uninitialized or non-UTF-8 data in str", self.path);
575+
try_validation!(
576+
self.ecx.read_str(mplace),
577+
"uninitialized or non-UTF-8 data in str",
578+
self.path
579+
);
577580
}
578581
ty::Array(tys, ..) | ty::Slice(tys)
579582
if {

0 commit comments

Comments
 (0)