Skip to content

Commit f33d02c

Browse files
authored
Rollup merge of rust-lang#63880 - RalfJung:miri-meta, r=oli-obk
Validation: check raw wide pointer metadata While I was at it, I also added a missing check for slices not to be too big. r? @oli-obk Fixes rust-lang/miri#918
2 parents 7e6cf90 + 04580b6 commit f33d02c

File tree

3 files changed

+177
-101
lines changed

3 files changed

+177
-101
lines changed

src/librustc_mir/interpret/validity.rs

+54-35
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ use std::hash::Hash;
1111

1212
use super::{
1313
GlobalAlloc, InterpResult,
14-
OpTy, Machine, InterpCx, ValueVisitor, MPlaceTy,
14+
Scalar, OpTy, Machine, InterpCx, ValueVisitor, MPlaceTy,
1515
};
1616

1717
macro_rules! throw_validation_failure {
@@ -250,6 +250,47 @@ impl<'rt, 'mir, 'tcx, M: Machine<'mir, 'tcx>> ValidityVisitor<'rt, 'mir, 'tcx, M
250250
self.path.truncate(path_len);
251251
Ok(())
252252
}
253+
254+
fn check_wide_ptr_meta(
255+
&mut self,
256+
meta: Option<Scalar<M::PointerTag>>,
257+
pointee: TyLayout<'tcx>,
258+
) -> InterpResult<'tcx> {
259+
let tail = self.ecx.tcx.struct_tail_erasing_lifetimes(pointee.ty, self.ecx.param_env);
260+
match tail.sty {
261+
ty::Dynamic(..) => {
262+
let vtable = meta.unwrap();
263+
try_validation!(
264+
self.ecx.memory.check_ptr_access(
265+
vtable,
266+
3*self.ecx.tcx.data_layout.pointer_size, // drop, size, align
267+
self.ecx.tcx.data_layout.pointer_align.abi,
268+
),
269+
"dangling or unaligned vtable pointer in wide pointer or too small vtable",
270+
self.path
271+
);
272+
try_validation!(self.ecx.read_drop_type_from_vtable(vtable),
273+
"invalid drop fn in vtable", self.path);
274+
try_validation!(self.ecx.read_size_and_align_from_vtable(vtable),
275+
"invalid size or align in vtable", self.path);
276+
// FIXME: More checks for the vtable.
277+
}
278+
ty::Slice(..) | ty::Str => {
279+
let _len = try_validation!(meta.unwrap().to_usize(self.ecx),
280+
"non-integer slice length in wide pointer", self.path);
281+
// We do not check that `len * elem_size <= isize::MAX`:
282+
// that is only required for references, and there it falls out of the
283+
// "dereferencable" check performed by Stacked Borrows.
284+
}
285+
ty::Foreign(..) => {
286+
// Unsized, but not wide.
287+
}
288+
_ =>
289+
bug!("Unexpected unsized type tail: {:?}", tail),
290+
}
291+
292+
Ok(())
293+
}
253294
}
254295

255296
impl<'rt, 'mir, 'tcx, M: Machine<'mir, 'tcx>> ValueVisitor<'mir, 'tcx, M>
@@ -341,56 +382,34 @@ impl<'rt, 'mir, 'tcx, M: Machine<'mir, 'tcx>> ValueVisitor<'mir, 'tcx, M>
341382
}
342383
}
343384
ty::RawPtr(..) => {
385+
// Check pointer part.
344386
if self.ref_tracking_for_consts.is_some() {
345387
// Integers/floats in CTFE: For consistency with integers, we do not
346388
// accept undef.
347389
let _ptr = try_validation!(value.to_scalar_ptr(),
348390
"undefined address in raw pointer", self.path);
349-
let _meta = try_validation!(value.to_meta(),
350-
"uninitialized data in raw fat pointer metadata", self.path);
351391
} else {
352392
// Remain consistent with `usize`: Accept anything.
353393
}
394+
395+
// Check metadata.
396+
let meta = try_validation!(value.to_meta(),
397+
"uninitialized data in wide pointer metadata", self.path);
398+
let layout = self.ecx.layout_of(value.layout.ty.builtin_deref(true).unwrap().ty)?;
399+
if layout.is_unsized() {
400+
self.check_wide_ptr_meta(meta, layout)?;
401+
}
354402
}
355403
_ if ty.is_box() || ty.is_region_ptr() => {
356-
// Handle fat pointers.
404+
// Handle wide pointers.
357405
// Check metadata early, for better diagnostics
358406
let ptr = try_validation!(value.to_scalar_ptr(),
359407
"undefined address in pointer", self.path);
360408
let meta = try_validation!(value.to_meta(),
361-
"uninitialized data in fat pointer metadata", self.path);
409+
"uninitialized data in wide pointer metadata", self.path);
362410
let layout = self.ecx.layout_of(value.layout.ty.builtin_deref(true).unwrap().ty)?;
363411
if layout.is_unsized() {
364-
let tail = self.ecx.tcx.struct_tail_erasing_lifetimes(layout.ty,
365-
self.ecx.param_env);
366-
match tail.sty {
367-
ty::Dynamic(..) => {
368-
let vtable = meta.unwrap();
369-
try_validation!(
370-
self.ecx.memory.check_ptr_access(
371-
vtable,
372-
3*self.ecx.tcx.data_layout.pointer_size, // drop, size, align
373-
self.ecx.tcx.data_layout.pointer_align.abi,
374-
),
375-
"dangling or unaligned vtable pointer or too small vtable",
376-
self.path
377-
);
378-
try_validation!(self.ecx.read_drop_type_from_vtable(vtable),
379-
"invalid drop fn in vtable", self.path);
380-
try_validation!(self.ecx.read_size_and_align_from_vtable(vtable),
381-
"invalid size or align in vtable", self.path);
382-
// FIXME: More checks for the vtable.
383-
}
384-
ty::Slice(..) | ty::Str => {
385-
try_validation!(meta.unwrap().to_usize(self.ecx),
386-
"non-integer slice length in fat pointer", self.path);
387-
}
388-
ty::Foreign(..) => {
389-
// Unsized, but not fat.
390-
}
391-
_ =>
392-
bug!("Unexpected unsized type tail: {:?}", tail),
393-
}
412+
self.check_wide_ptr_meta(meta, layout)?;
394413
}
395414
// Make sure this is dereferencable and all.
396415
let (size, align) = self.ecx.size_and_align_of(meta, layout)?

src/test/ui/consts/const-eval/union-ub-fat-ptr.rs src/test/ui/consts/const-eval/ub-wide-ptr.rs

+49-24
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
// ignore-tidy-linelength
12
#![allow(unused)]
23
#![allow(const_err)] // make sure we cannot allow away the errors tested here
34

@@ -28,7 +29,9 @@ struct BadSliceRepr {
2829
union SliceTransmute {
2930
repr: SliceRepr,
3031
bad: BadSliceRepr,
32+
addr: usize,
3133
slice: &'static [u8],
34+
raw_slice: *const [u8],
3235
str: &'static str,
3336
my_str: &'static MyStr,
3437
my_slice: &'static MySliceBool,
@@ -59,7 +62,9 @@ union DynTransmute {
5962
repr: DynRepr,
6063
repr2: DynRepr2,
6164
bad: BadDynRepr,
65+
addr: usize,
6266
rust: &'static dyn Trait,
67+
raw_rust: *const dyn Trait,
6368
}
6469

6570
trait Trait {}
@@ -72,39 +77,37 @@ struct MyStr(str);
7277
struct MySlice<T: ?Sized>(bool, T);
7378
type MySliceBool = MySlice<[bool]>;
7479

80+
// # str
7581
// OK
76-
const A: &str = unsafe { SliceTransmute { repr: SliceRepr { ptr: &42, len: 1 } }.str};
82+
const STR_VALID: &str = unsafe { SliceTransmute { repr: SliceRepr { ptr: &42, len: 1 } }.str};
7783
// bad str
78-
const B: &str = unsafe { SliceTransmute { repr: SliceRepr { ptr: &42, len: 999 } }.str};
84+
const STR_TOO_LONG: &str = unsafe { SliceTransmute { repr: SliceRepr { ptr: &42, len: 999 } }.str};
7985
//~^ ERROR it is undefined behavior to use this value
8086
// bad str
81-
const C: &str = unsafe { SliceTransmute { bad: BadSliceRepr { ptr: &42, len: &3 } }.str};
87+
const STR_LENGTH_PTR: &str = unsafe { SliceTransmute { bad: BadSliceRepr { ptr: &42, len: &3 } }.str};
8288
//~^ ERROR it is undefined behavior to use this value
8389
// bad str in user-defined unsized type
84-
const C2: &MyStr = unsafe { SliceTransmute { bad: BadSliceRepr { ptr: &42, len: &3 } }.my_str};
90+
const MY_STR_LENGTH_PTR: &MyStr = unsafe { SliceTransmute { bad: BadSliceRepr { ptr: &42, len: &3 } }.my_str};
8591
//~^ ERROR it is undefined behavior to use this value
8692

87-
// OK
88-
const A2: &[u8] = unsafe { SliceTransmute { repr: SliceRepr { ptr: &42, len: 1 } }.slice};
89-
// bad slice
90-
const B2: &[u8] = unsafe { SliceTransmute { repr: SliceRepr { ptr: &42, len: 999 } }.slice};
93+
// invalid UTF-8
94+
const J1: &str = unsafe { SliceTransmute { slice: &[0xFF] }.str };
9195
//~^ ERROR it is undefined behavior to use this value
92-
// bad slice
93-
const C3: &[u8] = unsafe { SliceTransmute { bad: BadSliceRepr { ptr: &42, len: &3 } }.slice};
96+
// invalid UTF-8 in user-defined str-like
97+
const J2: &MyStr = unsafe { SliceTransmute { slice: &[0xFF] }.my_str };
9498
//~^ ERROR it is undefined behavior to use this value
9599

96-
// bad trait object
97-
const D: &dyn Trait = unsafe { DynTransmute { repr: DynRepr { ptr: &92, vtable: &3 } }.rust};
98-
//~^ ERROR it is undefined behavior to use this value
99-
// bad trait object
100-
const E: &dyn Trait = unsafe { DynTransmute { repr2: DynRepr2 { ptr: &92, vtable: &3 } }.rust};
100+
// # slice
101+
// OK
102+
const SLICE_VALID: &[u8] = unsafe { SliceTransmute { repr: SliceRepr { ptr: &42, len: 1 } }.slice};
103+
// bad slice: length uninit
104+
const SLICE_LENGTH_UNINIT: &[u8] = unsafe { SliceTransmute { addr: 42 }.slice};
101105
//~^ ERROR it is undefined behavior to use this value
102-
// bad trait object
103-
const F: &dyn Trait = unsafe { DynTransmute { bad: BadDynRepr { ptr: &92, vtable: 3 } }.rust};
106+
// bad slice: length too big
107+
const SLICE_TOO_LONG: &[u8] = unsafe { SliceTransmute { repr: SliceRepr { ptr: &42, len: 999 } }.slice};
104108
//~^ ERROR it is undefined behavior to use this value
105-
106-
// bad data *inside* the trait object
107-
const G: &dyn Trait = &unsafe { BoolTransmute { val: 3 }.bl };
109+
// bad slice: length not an int
110+
const SLICE_LENGTH_PTR: &[u8] = unsafe { SliceTransmute { bad: BadSliceRepr { ptr: &42, len: &3 } }.slice};
108111
//~^ ERROR it is undefined behavior to use this value
109112

110113
// bad data *inside* the slice
@@ -120,12 +123,34 @@ const I2: &MySliceBool = &MySlice(unsafe { BoolTransmute { val: 3 }.bl }, [false
120123
const I3: &MySliceBool = &MySlice(true, [unsafe { BoolTransmute { val: 3 }.bl }]);
121124
//~^ ERROR it is undefined behavior to use this value
122125

123-
// invalid UTF-8
124-
const J1: &str = unsafe { SliceTransmute { slice: &[0xFF] }.str };
126+
// # raw slice
127+
const RAW_SLICE_VALID: *const [u8] = unsafe { SliceTransmute { repr: SliceRepr { ptr: &42, len: 1 } }.raw_slice}; // ok
128+
const RAW_SLICE_TOO_LONG: *const [u8] = unsafe { SliceTransmute { repr: SliceRepr { ptr: &42, len: 999 } }.raw_slice}; // ok because raw
129+
const RAW_SLICE_MUCH_TOO_LONG: *const [u8] = unsafe { SliceTransmute { repr: SliceRepr { ptr: &42, len: usize::max_value() } }.raw_slice}; // ok because raw
130+
const RAW_SLICE_LENGTH_UNINIT: *const [u8] = unsafe { SliceTransmute { addr: 42 }.raw_slice};
125131
//~^ ERROR it is undefined behavior to use this value
126-
// invalid UTF-8 in user-defined str-like
127-
const J2: &MyStr = unsafe { SliceTransmute { slice: &[0xFF] }.my_str };
132+
133+
// # trait object
134+
// bad trait object
135+
const D: &dyn Trait = unsafe { DynTransmute { repr: DynRepr { ptr: &92, vtable: &3 } }.rust};
136+
//~^ ERROR it is undefined behavior to use this value
137+
// bad trait object
138+
const E: &dyn Trait = unsafe { DynTransmute { repr2: DynRepr2 { ptr: &92, vtable: &3 } }.rust};
139+
//~^ ERROR it is undefined behavior to use this value
140+
// bad trait object
141+
const F: &dyn Trait = unsafe { DynTransmute { bad: BadDynRepr { ptr: &92, vtable: 3 } }.rust};
142+
//~^ ERROR it is undefined behavior to use this value
143+
144+
// bad data *inside* the trait object
145+
const G: &dyn Trait = &unsafe { BoolTransmute { val: 3 }.bl };
146+
//~^ ERROR it is undefined behavior to use this value
147+
148+
// # raw trait object
149+
const RAW_TRAIT_OBJ_VTABLE_NULL: *const dyn Trait = unsafe { DynTransmute { bad: BadDynRepr { ptr: &92, vtable: 0 } }.rust};
150+
//~^ ERROR it is undefined behavior to use this value
151+
const RAW_TRAIT_OBJ_VTABLE_INVALID: *const dyn Trait = unsafe { DynTransmute { repr2: DynRepr2 { ptr: &92, vtable: &3 } }.raw_rust};
128152
//~^ ERROR it is undefined behavior to use this value
153+
const RAW_TRAIT_OBJ_CONTENT_INVALID: *const dyn Trait = &unsafe { BoolTransmute { val: 3 }.bl } as *const _; // ok because raw
129154

130155
fn main() {
131156
}

0 commit comments

Comments
 (0)