Skip to content

Commit 1dc8b23

Browse files
authored
Rollup merge of #64014 - RalfJung:miri-slice, r=oli-obk
miri: detect too large dynamically sized objects Needed to make rust-lang/miri#929 pass. r? @oli-obk
2 parents ac71a7f + bb34749 commit 1dc8b23

File tree

7 files changed

+105
-59
lines changed

7 files changed

+105
-59
lines changed

src/librustc_mir/interpret/eval_context.rs

Lines changed: 15 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -442,27 +442,30 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
442442

443443
// Issue #27023: must add any necessary padding to `size`
444444
// (to make it a multiple of `align`) before returning it.
445-
//
446-
// Namely, the returned size should be, in C notation:
447-
//
448-
// `size + ((size & (align-1)) ? align : 0)`
449-
//
450-
// emulated via the semi-standard fast bit trick:
451-
//
452-
// `(size + (align-1)) & -align`
453-
454-
Ok(Some((size.align_to(align), align)))
445+
let size = size.align_to(align);
446+
447+
// Check if this brought us over the size limit.
448+
if size.bytes() >= self.tcx.data_layout().obj_size_bound() {
449+
throw_ub_format!("wide pointer metadata contains invalid information: \
450+
total size is bigger than largest supported object");
451+
}
452+
Ok(Some((size, align)))
455453
}
456454
ty::Dynamic(..) => {
457455
let vtable = metadata.expect("dyn trait fat ptr must have vtable");
458-
// the second entry in the vtable is the dynamic size of the object.
456+
// Read size and align from vtable (already checks size).
459457
Ok(Some(self.read_size_and_align_from_vtable(vtable)?))
460458
}
461459

462460
ty::Slice(_) | ty::Str => {
463461
let len = metadata.expect("slice fat ptr must have vtable").to_usize(self)?;
464462
let elem = layout.field(self, 0)?;
465-
Ok(Some((elem.size * len, elem.align.abi)))
463+
464+
// Make sure the slice is not too big.
465+
let size = elem.size.checked_mul(len, &*self.tcx)
466+
.ok_or_else(|| err_ub_format!("invalid slice: \
467+
total size is bigger than largest supported object"))?;
468+
Ok(Some((size, elem.align.abi)))
466469
}
467470

468471
ty::Foreign(_) => {

src/librustc_mir/interpret/traits.rs

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
use rustc::ty::{self, Ty, Instance, TypeFoldable};
2-
use rustc::ty::layout::{Size, Align, LayoutOf};
2+
use rustc::ty::layout::{Size, Align, LayoutOf, HasDataLayout};
33
use rustc::mir::interpret::{Scalar, Pointer, InterpResult, PointerArithmetic,};
44

55
use super::{InterpCx, Machine, MemoryKind, FnVal};
@@ -151,6 +151,11 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
151151
vtable.offset(pointer_size * 2, self)?,
152152
)?.not_undef()?;
153153
let align = self.force_bits(align, pointer_size)? as u64;
154+
155+
if size >= self.tcx.data_layout().obj_size_bound() {
156+
throw_ub_format!("invalid vtable: \
157+
size is bigger than largest supported object");
158+
}
154159
Ok((Size::from_bytes(size), Align::from_bytes(align).unwrap()))
155160
}
156161
}

src/librustc_mir/interpret/validity.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,9 @@
1+
//! Check the validity invariant of a given value, and tell the user
2+
//! where in the value it got violated.
3+
//! In const context, this goes even further and tries to approximate const safety.
4+
//! That's useful because it means other passes (e.g. promotion) can rely on `const`s
5+
//! to be const-safe.
6+
17
use std::fmt::Write;
28
use std::ops::RangeInclusive;
39

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
#![feature(const_transmute, const_raw_ptr_deref)]
2+
3+
use std::{mem, usize};
4+
5+
// Make sure we error with the right kind of error on a too large slice.
6+
const TEST: () = { unsafe { //~ NOTE
7+
let slice: *const [u8] = mem::transmute((1usize, usize::MAX));
8+
let _val = &*slice; //~ ERROR: any use of this value will cause an error
9+
//~^ NOTE: total size is bigger than largest supported object
10+
//~^^ on by default
11+
} };
12+
13+
fn main() {}
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
error: any use of this value will cause an error
2+
--> $DIR/dangling.rs:8:16
3+
|
4+
LL | / const TEST: () = { unsafe {
5+
LL | | let slice: *const [u8] = mem::transmute((1usize, usize::MAX));
6+
LL | | let _val = &*slice;
7+
| | ^^^^^^^ invalid slice: total size is bigger than largest supported object
8+
LL | |
9+
LL | |
10+
LL | | } };
11+
| |____-
12+
|
13+
= note: `#[deny(const_err)]` on by default
14+
15+
error: aborting due to previous error
16+

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

Lines changed: 13 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
// normalize-stderr-test "allocation \d+" -> "allocation N"
88
// normalize-stderr-test "size \d+" -> "size N"
99

10+
#[repr(C)]
1011
union BoolTransmute {
1112
val: u8,
1213
bl: bool,
@@ -26,6 +27,7 @@ struct BadSliceRepr {
2627
len: &'static u8,
2728
}
2829

30+
#[repr(C)]
2931
union SliceTransmute {
3032
repr: SliceRepr,
3133
bad: BadSliceRepr,
@@ -58,6 +60,7 @@ struct BadDynRepr {
5860
vtable: usize,
5961
}
6062

63+
#[repr(C)]
6164
union DynTransmute {
6265
repr: DynRepr,
6366
repr2: DynRepr2,
@@ -91,10 +94,10 @@ const MY_STR_LENGTH_PTR: &MyStr = unsafe { SliceTransmute { bad: BadSliceRepr {
9194
//~^ ERROR it is undefined behavior to use this value
9295

9396
// invalid UTF-8
94-
const J1: &str = unsafe { SliceTransmute { slice: &[0xFF] }.str };
97+
const STR_NO_UTF8: &str = unsafe { SliceTransmute { slice: &[0xFF] }.str };
9598
//~^ ERROR it is undefined behavior to use this value
9699
// invalid UTF-8 in user-defined str-like
97-
const J2: &MyStr = unsafe { SliceTransmute { slice: &[0xFF] }.my_str };
100+
const MYSTR_NO_UTF8: &MyStr = unsafe { SliceTransmute { slice: &[0xFF] }.my_str };
98101
//~^ ERROR it is undefined behavior to use this value
99102

100103
// # slice
@@ -111,16 +114,16 @@ const SLICE_LENGTH_PTR: &[u8] = unsafe { SliceTransmute { bad: BadSliceRepr { pt
111114
//~^ ERROR it is undefined behavior to use this value
112115

113116
// bad data *inside* the slice
114-
const H: &[bool] = &[unsafe { BoolTransmute { val: 3 }.bl }];
117+
const SLICE_CONTENT_INVALID: &[bool] = &[unsafe { BoolTransmute { val: 3 }.bl }];
115118
//~^ ERROR it is undefined behavior to use this value
116119

117120
// good MySliceBool
118-
const I1: &MySliceBool = &MySlice(true, [false]);
121+
const MYSLICE_GOOD: &MySliceBool = &MySlice(true, [false]);
119122
// bad: sized field is not okay
120-
const I2: &MySliceBool = &MySlice(unsafe { BoolTransmute { val: 3 }.bl }, [false]);
123+
const MYSLICE_PREFIX_BAD: &MySliceBool = &MySlice(unsafe { BoolTransmute { val: 3 }.bl }, [false]);
121124
//~^ ERROR it is undefined behavior to use this value
122125
// bad: unsized part is not okay
123-
const I3: &MySliceBool = &MySlice(true, [unsafe { BoolTransmute { val: 3 }.bl }]);
126+
const MYSLICE_SUFFIX_BAD: &MySliceBool = &MySlice(true, [unsafe { BoolTransmute { val: 3 }.bl }]);
124127
//~^ ERROR it is undefined behavior to use this value
125128

126129
// # raw slice
@@ -132,17 +135,17 @@ const RAW_SLICE_LENGTH_UNINIT: *const [u8] = unsafe { SliceTransmute { addr: 42
132135

133136
// # trait object
134137
// bad trait object
135-
const D: &dyn Trait = unsafe { DynTransmute { repr: DynRepr { ptr: &92, vtable: &3 } }.rust};
138+
const TRAIT_OBJ_SHORT_VTABLE_1: &dyn Trait = unsafe { DynTransmute { repr: DynRepr { ptr: &92, vtable: &3 } }.rust};
136139
//~^ ERROR it is undefined behavior to use this value
137140
// bad trait object
138-
const E: &dyn Trait = unsafe { DynTransmute { repr2: DynRepr2 { ptr: &92, vtable: &3 } }.rust};
141+
const TRAIT_OBJ_SHORT_VTABLE_2: &dyn Trait = unsafe { DynTransmute { repr2: DynRepr2 { ptr: &92, vtable: &3 } }.rust};
139142
//~^ ERROR it is undefined behavior to use this value
140143
// bad trait object
141-
const F: &dyn Trait = unsafe { DynTransmute { bad: BadDynRepr { ptr: &92, vtable: 3 } }.rust};
144+
const TRAIT_OBJ_INT_VTABLE: &dyn Trait = unsafe { DynTransmute { bad: BadDynRepr { ptr: &92, vtable: 3 } }.rust};
142145
//~^ ERROR it is undefined behavior to use this value
143146

144147
// bad data *inside* the trait object
145-
const G: &dyn Trait = &unsafe { BoolTransmute { val: 3 }.bl };
148+
const TRAIT_OBJ_CONTENT_INVALID: &dyn Trait = &unsafe { BoolTransmute { val: 3 }.bl };
146149
//~^ ERROR it is undefined behavior to use this value
147150

148151
// # raw trait object

0 commit comments

Comments
 (0)