Skip to content

Commit

Permalink
Rollup merge of #64014 - RalfJung:miri-slice, r=oli-obk
Browse files Browse the repository at this point in the history
 miri: detect too large dynamically sized objects

Needed to make rust-lang/miri#929 pass.

r? @oli-obk
  • Loading branch information
Centril authored Aug 30, 2019
2 parents ac71a7f + bb34749 commit 1dc8b23
Show file tree
Hide file tree
Showing 7 changed files with 105 additions and 59 deletions.
27 changes: 15 additions & 12 deletions src/librustc_mir/interpret/eval_context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -442,27 +442,30 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {

// Issue #27023: must add any necessary padding to `size`
// (to make it a multiple of `align`) before returning it.
//
// Namely, the returned size should be, in C notation:
//
// `size + ((size & (align-1)) ? align : 0)`
//
// emulated via the semi-standard fast bit trick:
//
// `(size + (align-1)) & -align`

Ok(Some((size.align_to(align), align)))
let size = size.align_to(align);

// Check if this brought us over the size limit.
if size.bytes() >= self.tcx.data_layout().obj_size_bound() {
throw_ub_format!("wide pointer metadata contains invalid information: \
total size is bigger than largest supported object");
}
Ok(Some((size, align)))
}
ty::Dynamic(..) => {
let vtable = metadata.expect("dyn trait fat ptr must have vtable");
// the second entry in the vtable is the dynamic size of the object.
// Read size and align from vtable (already checks size).
Ok(Some(self.read_size_and_align_from_vtable(vtable)?))
}

ty::Slice(_) | ty::Str => {
let len = metadata.expect("slice fat ptr must have vtable").to_usize(self)?;
let elem = layout.field(self, 0)?;
Ok(Some((elem.size * len, elem.align.abi)))

// Make sure the slice is not too big.
let size = elem.size.checked_mul(len, &*self.tcx)
.ok_or_else(|| err_ub_format!("invalid slice: \
total size is bigger than largest supported object"))?;
Ok(Some((size, elem.align.abi)))
}

ty::Foreign(_) => {
Expand Down
7 changes: 6 additions & 1 deletion src/librustc_mir/interpret/traits.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
use rustc::ty::{self, Ty, Instance, TypeFoldable};
use rustc::ty::layout::{Size, Align, LayoutOf};
use rustc::ty::layout::{Size, Align, LayoutOf, HasDataLayout};
use rustc::mir::interpret::{Scalar, Pointer, InterpResult, PointerArithmetic,};

use super::{InterpCx, Machine, MemoryKind, FnVal};
Expand Down Expand Up @@ -151,6 +151,11 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
vtable.offset(pointer_size * 2, self)?,
)?.not_undef()?;
let align = self.force_bits(align, pointer_size)? as u64;

if size >= self.tcx.data_layout().obj_size_bound() {
throw_ub_format!("invalid vtable: \
size is bigger than largest supported object");
}
Ok((Size::from_bytes(size), Align::from_bytes(align).unwrap()))
}
}
6 changes: 6 additions & 0 deletions src/librustc_mir/interpret/validity.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,9 @@
//! Check the validity invariant of a given value, and tell the user
//! where in the value it got violated.
//! In const context, this goes even further and tries to approximate const safety.
//! That's useful because it means other passes (e.g. promotion) can rely on `const`s
//! to be const-safe.
use std::fmt::Write;
use std::ops::RangeInclusive;

Expand Down
13 changes: 13 additions & 0 deletions src/test/ui/consts/const-eval/dangling.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
#![feature(const_transmute, const_raw_ptr_deref)]

use std::{mem, usize};

// Make sure we error with the right kind of error on a too large slice.
const TEST: () = { unsafe { //~ NOTE
let slice: *const [u8] = mem::transmute((1usize, usize::MAX));
let _val = &*slice; //~ ERROR: any use of this value will cause an error
//~^ NOTE: total size is bigger than largest supported object
//~^^ on by default
} };

fn main() {}
16 changes: 16 additions & 0 deletions src/test/ui/consts/const-eval/dangling.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
error: any use of this value will cause an error
--> $DIR/dangling.rs:8:16
|
LL | / const TEST: () = { unsafe {
LL | | let slice: *const [u8] = mem::transmute((1usize, usize::MAX));
LL | | let _val = &*slice;
| | ^^^^^^^ invalid slice: total size is bigger than largest supported object
LL | |
LL | |
LL | | } };
| |____-
|
= note: `#[deny(const_err)]` on by default

error: aborting due to previous error

23 changes: 13 additions & 10 deletions src/test/ui/consts/const-eval/ub-wide-ptr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
// normalize-stderr-test "allocation \d+" -> "allocation N"
// normalize-stderr-test "size \d+" -> "size N"

#[repr(C)]
union BoolTransmute {
val: u8,
bl: bool,
Expand All @@ -26,6 +27,7 @@ struct BadSliceRepr {
len: &'static u8,
}

#[repr(C)]
union SliceTransmute {
repr: SliceRepr,
bad: BadSliceRepr,
Expand Down Expand Up @@ -58,6 +60,7 @@ struct BadDynRepr {
vtable: usize,
}

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

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

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

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

// good MySliceBool
const I1: &MySliceBool = &MySlice(true, [false]);
const MYSLICE_GOOD: &MySliceBool = &MySlice(true, [false]);
// bad: sized field is not okay
const I2: &MySliceBool = &MySlice(unsafe { BoolTransmute { val: 3 }.bl }, [false]);
const MYSLICE_PREFIX_BAD: &MySliceBool = &MySlice(unsafe { BoolTransmute { val: 3 }.bl }, [false]);
//~^ ERROR it is undefined behavior to use this value
// bad: unsized part is not okay
const I3: &MySliceBool = &MySlice(true, [unsafe { BoolTransmute { val: 3 }.bl }]);
const MYSLICE_SUFFIX_BAD: &MySliceBool = &MySlice(true, [unsafe { BoolTransmute { val: 3 }.bl }]);
//~^ ERROR it is undefined behavior to use this value

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

// # trait object
// bad trait object
const D: &dyn Trait = unsafe { DynTransmute { repr: DynRepr { ptr: &92, vtable: &3 } }.rust};
const TRAIT_OBJ_SHORT_VTABLE_1: &dyn Trait = unsafe { DynTransmute { repr: DynRepr { ptr: &92, vtable: &3 } }.rust};
//~^ ERROR it is undefined behavior to use this value
// bad trait object
const E: &dyn Trait = unsafe { DynTransmute { repr2: DynRepr2 { ptr: &92, vtable: &3 } }.rust};
const TRAIT_OBJ_SHORT_VTABLE_2: &dyn Trait = unsafe { DynTransmute { repr2: DynRepr2 { ptr: &92, vtable: &3 } }.rust};
//~^ ERROR it is undefined behavior to use this value
// bad trait object
const F: &dyn Trait = unsafe { DynTransmute { bad: BadDynRepr { ptr: &92, vtable: 3 } }.rust};
const TRAIT_OBJ_INT_VTABLE: &dyn Trait = unsafe { DynTransmute { bad: BadDynRepr { ptr: &92, vtable: 3 } }.rust};
//~^ ERROR it is undefined behavior to use this value

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

// # raw trait object
Expand Down
Loading

0 comments on commit 1dc8b23

Please sign in to comment.