Skip to content

Commit 6d4840e

Browse files
authored
Merge pull request rust-lang#342 from RalfJung/mir-validate
validation: check that int, float etc. are not undef
2 parents 1fc3a00 + bc240ff commit 6d4840e

File tree

9 files changed

+49
-8
lines changed

9 files changed

+49
-8
lines changed

src/librustc_mir/interpret/eval_context.rs

+2
Original file line numberDiff line numberDiff line change
@@ -1483,6 +1483,7 @@ impl<'a, 'tcx, M: Machine<'tcx>> EvalContext<'a, 'tcx, M> {
14831483
Value::ByRef { .. } => bug!("follow_by_ref_value can't result in `ByRef`"),
14841484

14851485
Value::ByVal(primval) => {
1486+
// TODO: Do we really want insta-UB here?
14861487
self.ensure_valid_value(primval, ty)?;
14871488
Ok(primval)
14881489
}
@@ -1817,6 +1818,7 @@ impl<'a, 'tcx, M: Machine<'tcx>> EvalContext<'a, 'tcx, M> {
18171818
let val = match val {
18181819
PrimVal::Bytes(0) => false,
18191820
PrimVal::Bytes(1) => true,
1821+
// TODO: This seems a little overeager, should reading at bool type already be UB?
18201822
_ => return err!(InvalidBool),
18211823
};
18221824
PrimVal::from_bool(val)

src/librustc_mir/interpret/validation.rs

+18-4
Original file line numberDiff line numberDiff line change
@@ -492,12 +492,22 @@ impl<'a, 'tcx, M: Machine<'tcx>> EvalContext<'a, 'tcx, M> {
492492
let res = do catch {
493493
match query.ty.sty {
494494
TyInt(_) | TyUint(_) | TyRawPtr(_) => {
495-
// TODO: Make sure these are not undef.
496-
// We could do a bounds-check and other sanity checks on the lvalue, but it would be a bug in miri for this to ever fail.
495+
if mode.acquiring() {
496+
// Make sure we can read this.
497+
let val = self.read_lvalue(query.lval.1)?;
498+
self.follow_by_ref_value(val, query.ty)?;
499+
// FIXME: It would be great to rule out Undef here, but that doesn't actually work.
500+
// Passing around undef data is a thing that e.g. Vec::extend_with does.
501+
}
497502
Ok(())
498503
}
499-
TyBool | TyFloat(_) | TyChar | TyStr => {
500-
// TODO: Check if these are valid bool/float/codepoint/UTF-8, respectively (and in particular, not undef).
504+
TyBool | TyFloat(_) | TyChar => {
505+
if mode.acquiring() {
506+
let val = self.read_lvalue(query.lval.1)?;
507+
let val = self.value_to_primval(ValTy { value: val, ty: query.ty })?;
508+
val.to_bytes()?;
509+
// TODO: Check if these are valid bool/float/codepoint/UTF-8
510+
}
501511
Ok(())
502512
}
503513
TyNever => err!(ValidationFailure(format!("The empty type is never valid."))),
@@ -542,6 +552,10 @@ impl<'a, 'tcx, M: Machine<'tcx>> EvalContext<'a, 'tcx, M> {
542552
}
543553

544554
// Compound types
555+
TyStr => {
556+
// TODO: Validate strings
557+
Ok(())
558+
}
545559
TySlice(elem_ty) => {
546560
let len = match query.lval.1 {
547561
Lvalue::Ptr { extra: LvalueExtra::Length(len), .. } => len,

tests/compile-fail-fullmir/undefined_byte_read.rs

+3
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,6 @@
1+
// This should fail even without validation
2+
// compile-flags: -Zmir-emit-validate=0
3+
14
fn main() {
25
let v: Vec<u8> = Vec::with_capacity(10);
36
let undef = unsafe { *v.get_unchecked(5) };

tests/compile-fail/invalid_bool.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
11
fn main() {
2-
let b = unsafe { std::mem::transmute::<u8, bool>(2) };
3-
if b { unreachable!() } else { unreachable!() } //~ ERROR: invalid boolean value read
2+
let b = unsafe { std::mem::transmute::<u8, bool>(2) }; //~ ERROR: invalid boolean value read
3+
if b { unreachable!() } else { unreachable!() }
44
}

tests/compile-fail/match_char.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
fn main() {
22
assert!(std::char::from_u32(-1_i32 as u32).is_none());
3-
match unsafe { std::mem::transmute::<i32, char>(-1) } {
4-
'a' => {}, //~ERROR tried to interpret an invalid 32-bit value as a char: 4294967295
3+
match unsafe { std::mem::transmute::<i32, char>(-1) } { //~ERROR tried to interpret an invalid 32-bit value as a char: 4294967295
4+
'a' => {},
55
'b' => {},
66
_ => {},
77
}

tests/compile-fail/reference_to_packed.rs

+3
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,6 @@
1+
// This should fail even without validation
2+
// compile-flags: -Zmir-emit-validate=0
3+
14
#![allow(dead_code, unused_variables)]
25

36
#[repr(packed)]

tests/compile-fail/transmute_fat.rs

+2
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
// This should fail even without validation
2+
// compile-flags: -Zmir-emit-validate=0
13
#![feature(i128_type)]
24

35
fn main() {
+14
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
#![allow(unused_variables)]
2+
// error-pattern: attempted to read undefined bytes
3+
4+
mod safe {
5+
use std::mem;
6+
7+
pub(crate) fn make_float() -> f32 {
8+
unsafe { mem::uninitialized() }
9+
}
10+
}
11+
12+
fn main() {
13+
let _x = safe::make_float();
14+
}

tests/run-pass/move-undef-primval.rs

+3
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,6 @@
1+
// Moving around undef is not allowed by validation
2+
// compile-flags: -Zmir-emit-validate=0
3+
14
struct Foo {
25
_inner: i32,
36
}

0 commit comments

Comments
 (0)