Skip to content

Commit 2ea6663

Browse files
committed
validation: check that int, float etc. are not undef
1 parent 1fc3a00 commit 2ea6663

File tree

8 files changed

+42
-8
lines changed

8 files changed

+42
-8
lines changed

src/librustc_mir/interpret/eval_context.rs

Lines changed: 2 additions & 0 deletions
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

Lines changed: 25 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -492,12 +492,29 @@ 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 there is no undef
497+
let val = self.read_lvalue(query.lval.1)?;
498+
// This is essentially value_to_primval with support for fat pointers
499+
let has_undef = match self.follow_by_ref_value(val, query.ty)? {
500+
Value::ByRef { .. } => bug!("follow_by_ref_value can't result in `ByRef`"),
501+
Value::ByVal(primval) => primval.is_undef(),
502+
Value::ByValPair(primval1, primval2) =>
503+
primval1.is_undef() || primval2.is_undef()
504+
};
505+
if has_undef {
506+
return err!(ReadUndefBytes);
507+
}
508+
}
497509
Ok(())
498510
}
499-
TyBool | TyFloat(_) | TyChar | TyStr => {
500-
// TODO: Check if these are valid bool/float/codepoint/UTF-8, respectively (and in particular, not undef).
511+
TyBool | TyFloat(_) | TyChar => {
512+
if mode.acquiring() {
513+
let val = self.read_lvalue(query.lval.1)?;
514+
let val = self.value_to_primval(ValTy { value: val, ty: query.ty })?;
515+
let _val = val.to_bytes()?;
516+
// TODO: Check if these are valid bool/float/codepoint/UTF-8
517+
}
501518
Ok(())
502519
}
503520
TyNever => err!(ValidationFailure(format!("The empty type is never valid."))),
@@ -542,6 +559,10 @@ impl<'a, 'tcx, M: Machine<'tcx>> EvalContext<'a, 'tcx, M> {
542559
}
543560

544561
// Compound types
562+
TyStr => {
563+
// TODO: Validate strings
564+
Ok(())
565+
}
545566
TySlice(elem_ty) => {
546567
let len = match query.lval.1 {
547568
Lvalue::Ptr { extra: LvalueExtra::Length(len), .. } => len,

tests/compile-fail-fullmir/undefined_byte_read.rs

Lines changed: 3 additions & 0 deletions
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

Lines changed: 2 additions & 2 deletions
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

Lines changed: 2 additions & 2 deletions
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

Lines changed: 3 additions & 0 deletions
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

Lines changed: 2 additions & 0 deletions
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() {

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

Lines changed: 3 additions & 0 deletions
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)