Skip to content

Commit 5099933

Browse files
committed
move validation to its own file
1 parent f2aeb5b commit 5099933

File tree

3 files changed

+346
-331
lines changed

3 files changed

+346
-331
lines changed

src/librustc_mir/interpret/eval_context.rs

Lines changed: 2 additions & 331 deletions
Original file line numberDiff line numberDiff line change
@@ -7,15 +7,15 @@ use rustc::hir::def::Def;
77
use rustc::hir::map::definitions::DefPathData;
88
use rustc::mir;
99
use rustc::ty::layout::{
10-
self, Size, Align, HasDataLayout, LayoutOf, TyLayout, Primitive
10+
self, Size, Align, HasDataLayout, LayoutOf, TyLayout
1111
};
1212
use rustc::ty::subst::{Subst, Substs};
1313
use rustc::ty::{self, Ty, TyCtxt, TypeFoldable};
1414
use rustc::ty::query::TyCtxtAt;
1515
use rustc_data_structures::fx::{FxHashSet, FxHasher};
1616
use rustc_data_structures::indexed_vec::IndexVec;
1717
use rustc::mir::interpret::{
18-
GlobalId, Scalar, FrameInfo, AllocType,
18+
GlobalId, Scalar, FrameInfo,
1919
EvalResult, EvalErrorKind,
2020
ScalarMaybeUndef,
2121
truncate, sign_extend,
@@ -29,31 +29,6 @@ use super::{
2929
Memory, Machine
3030
};
3131

32-
macro_rules! validation_failure{
33-
($what:expr, $where:expr, $details:expr) => {{
34-
let where_ = if $where.is_empty() {
35-
String::new()
36-
} else {
37-
format!(" at {}", $where)
38-
};
39-
err!(ValidationFailure(format!(
40-
"encountered {}{}, but expected {}",
41-
$what, where_, $details,
42-
)))
43-
}};
44-
($what:expr, $where:expr) => {{
45-
let where_ = if $where.is_empty() {
46-
String::new()
47-
} else {
48-
format!(" at {}", $where)
49-
};
50-
err!(ValidationFailure(format!(
51-
"encountered {}{}",
52-
$what, where_,
53-
)))
54-
}};
55-
}
56-
5732
pub struct EvalContext<'a, 'mir, 'tcx: 'a + 'mir, M: Machine<'mir, 'tcx>> {
5833
/// Stores the `Machine` instance.
5934
pub machine: M,
@@ -670,243 +645,6 @@ impl<'a, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M
670645
self.tcx.const_eval(param_env.and(gid)).map_err(|err| EvalErrorKind::ReferencedConstant(err).into())
671646
}
672647

673-
fn validate_scalar(
674-
&self,
675-
value: ScalarMaybeUndef,
676-
size: Size,
677-
scalar: &layout::Scalar,
678-
path: &str,
679-
ty: Ty,
680-
) -> EvalResult<'tcx> {
681-
trace!("validate scalar: {:#?}, {:#?}, {:#?}, {}", value, size, scalar, ty);
682-
let (lo, hi) = scalar.valid_range.clone().into_inner();
683-
684-
let value = match value {
685-
ScalarMaybeUndef::Scalar(scalar) => scalar,
686-
ScalarMaybeUndef::Undef => return validation_failure!("undefined bytes", path),
687-
};
688-
689-
let bits = match value {
690-
Scalar::Bits { bits, size: value_size } => {
691-
assert_eq!(value_size as u64, size.bytes());
692-
bits
693-
},
694-
Scalar::Ptr(_) => {
695-
let ptr_size = self.memory.pointer_size();
696-
let ptr_max = u128::max_value() >> (128 - ptr_size.bits());
697-
return if lo > hi {
698-
if lo - hi == 1 {
699-
// no gap, all values are ok
700-
Ok(())
701-
} else if hi < ptr_max || lo > 1 {
702-
let max = u128::max_value() >> (128 - size.bits());
703-
validation_failure!(
704-
"pointer",
705-
path,
706-
format!("something in the range {:?} or {:?}", 0..=lo, hi..=max)
707-
)
708-
} else {
709-
Ok(())
710-
}
711-
} else if hi < ptr_max || lo > 1 {
712-
validation_failure!(
713-
"pointer",
714-
path,
715-
format!("something in the range {:?}", scalar.valid_range)
716-
)
717-
} else {
718-
Ok(())
719-
};
720-
},
721-
};
722-
723-
// char gets a special treatment, because its number space is not contiguous so `TyLayout`
724-
// has no special checks for chars
725-
match ty.sty {
726-
ty::TyChar => {
727-
debug_assert_eq!(size.bytes(), 4);
728-
if ::std::char::from_u32(bits as u32).is_none() {
729-
return err!(InvalidChar(bits));
730-
}
731-
}
732-
_ => {},
733-
}
734-
735-
use std::ops::RangeInclusive;
736-
let in_range = |bound: RangeInclusive<u128>| bound.contains(&bits);
737-
if lo > hi {
738-
if in_range(0..=hi) || in_range(lo..=u128::max_value()) {
739-
Ok(())
740-
} else {
741-
validation_failure!(
742-
bits,
743-
path,
744-
format!("something in the range {:?} or {:?}", ..=hi, lo..)
745-
)
746-
}
747-
} else {
748-
if in_range(scalar.valid_range.clone()) {
749-
Ok(())
750-
} else {
751-
validation_failure!(
752-
bits,
753-
path,
754-
format!("something in the range {:?}", scalar.valid_range)
755-
)
756-
}
757-
}
758-
}
759-
760-
/// This function checks the memory where `ptr` points to.
761-
/// It will error if the bits at the destination do not match the ones described by the layout.
762-
pub fn validate_mplace(
763-
&self,
764-
dest: MPlaceTy<'tcx>,
765-
path: String,
766-
seen: &mut FxHashSet<(MPlaceTy<'tcx>)>,
767-
todo: &mut Vec<(MPlaceTy<'tcx>, String)>,
768-
) -> EvalResult<'tcx> {
769-
self.memory.dump_alloc(dest.to_ptr()?.alloc_id);
770-
trace!("validate_mplace: {:?}, {:#?}", *dest, dest.layout);
771-
772-
// Find the right variant
773-
let (variant, dest) = match dest.layout.variants {
774-
layout::Variants::NicheFilling { niche: ref tag, .. } |
775-
layout::Variants::Tagged { ref tag, .. } => {
776-
let size = tag.value.size(self);
777-
// we first read the tag value as scalar, to be able to validate it
778-
let tag_mplace = self.mplace_field(dest, 0)?;
779-
let tag_value = self.read_scalar(tag_mplace.into())?;
780-
let path = format!("{}.TAG", path);
781-
self.validate_scalar(
782-
tag_value, size, tag, &path, tag_mplace.layout.ty
783-
)?;
784-
// then we read it again to get the index, to continue
785-
let variant = self.read_discriminant_as_variant_index(dest.into())?;
786-
let dest = self.mplace_downcast(dest, variant)?;
787-
trace!("variant layout: {:#?}", dest.layout);
788-
(variant, dest)
789-
},
790-
layout::Variants::Single { index } => {
791-
(index, dest)
792-
}
793-
};
794-
795-
// Validate all fields
796-
match dest.layout.fields {
797-
// primitives are unions with zero fields
798-
layout::FieldPlacement::Union(0) => {
799-
match dest.layout.abi {
800-
// nothing to do, whatever the pointer points to, it is never going to be read
801-
layout::Abi::Uninhabited => validation_failure!("a value of an uninhabited type", path),
802-
// check that the scalar is a valid pointer or that its bit range matches the
803-
// expectation.
804-
layout::Abi::Scalar(ref scalar_layout) => {
805-
let size = scalar_layout.value.size(self);
806-
let value = self.read_value(dest.into())?;
807-
let scalar = value.to_scalar_or_undef();
808-
self.validate_scalar(scalar, size, scalar_layout, &path, dest.layout.ty)?;
809-
if scalar_layout.value == Primitive::Pointer {
810-
// ignore integer pointers, we can't reason about the final hardware
811-
if let Scalar::Ptr(ptr) = scalar.not_undef()? {
812-
let alloc_kind = self.tcx.alloc_map.lock().get(ptr.alloc_id);
813-
if let Some(AllocType::Static(did)) = alloc_kind {
814-
// statics from other crates are already checked
815-
// extern statics should not be validated as they have no body
816-
if !did.is_local() || self.tcx.is_foreign_item(did) {
817-
return Ok(());
818-
}
819-
}
820-
if value.layout.ty.builtin_deref(false).is_some() {
821-
trace!("Recursing below ptr {:#?}", value);
822-
let ptr_place = self.ref_to_mplace(value)?;
823-
// we have not encountered this pointer+layout combination before
824-
if seen.insert(ptr_place) {
825-
todo.push((ptr_place, format!("(*{})", path)))
826-
}
827-
}
828-
}
829-
}
830-
Ok(())
831-
},
832-
_ => bug!("bad abi for FieldPlacement::Union(0): {:#?}", dest.layout.abi),
833-
}
834-
}
835-
layout::FieldPlacement::Union(_) => {
836-
// We can't check unions, their bits are allowed to be anything.
837-
// The fields don't need to correspond to any bit pattern of the union's fields.
838-
// See https://github.com/rust-lang/rust/issues/32836#issuecomment-406875389
839-
Ok(())
840-
},
841-
layout::FieldPlacement::Array { count, .. } => {
842-
for i in 0..count {
843-
let mut path = path.clone();
844-
self.dump_field_name(&mut path, dest.layout.ty, i as usize, variant).unwrap();
845-
let field = self.mplace_field(dest, i)?;
846-
self.validate_mplace(field, path, seen, todo)?;
847-
}
848-
Ok(())
849-
},
850-
layout::FieldPlacement::Arbitrary { ref offsets, .. } => {
851-
// fat pointers need special treatment
852-
match dest.layout.ty.builtin_deref(false).map(|tam| &tam.ty.sty) {
853-
| Some(ty::TyStr)
854-
| Some(ty::TySlice(_)) => {
855-
// check the length (for nicer error messages)
856-
let len_mplace = self.mplace_field(dest, 1)?;
857-
let len = self.read_scalar(len_mplace.into())?;
858-
let len = match len.to_bits(len_mplace.layout.size) {
859-
Err(_) => return validation_failure!("length is not a valid integer", path),
860-
Ok(len) => len as u64,
861-
};
862-
// get the fat ptr, and recursively check it
863-
let ptr = self.ref_to_mplace(self.read_value(dest.into())?)?;
864-
assert_eq!(ptr.extra, PlaceExtra::Length(len));
865-
let unpacked_ptr = self.unpack_unsized_mplace(ptr)?;
866-
if seen.insert(unpacked_ptr) {
867-
let mut path = path.clone();
868-
self.dump_field_name(&mut path, dest.layout.ty, 0, 0).unwrap();
869-
todo.push((unpacked_ptr, path))
870-
}
871-
},
872-
Some(ty::TyDynamic(..)) => {
873-
// check the vtable (for nicer error messages)
874-
let vtable = self.read_scalar(self.mplace_field(dest, 1)?.into())?;
875-
let vtable = match vtable.to_ptr() {
876-
Err(_) => return validation_failure!("vtable address is not a pointer", path),
877-
Ok(vtable) => vtable,
878-
};
879-
// get the fat ptr, and recursively check it
880-
let ptr = self.ref_to_mplace(self.read_value(dest.into())?)?;
881-
assert_eq!(ptr.extra, PlaceExtra::Vtable(vtable));
882-
let unpacked_ptr = self.unpack_unsized_mplace(ptr)?;
883-
if seen.insert(unpacked_ptr) {
884-
let mut path = path.clone();
885-
self.dump_field_name(&mut path, dest.layout.ty, 0, 0).unwrap();
886-
todo.push((unpacked_ptr, path))
887-
}
888-
// FIXME: More checks for the vtable... making sure it is exactly
889-
// the one one would expect for this type.
890-
},
891-
Some(ty) =>
892-
bug!("Unexpected fat pointer target type {:?}", ty),
893-
None => {
894-
// Not a pointer, perform regular aggregate handling below
895-
for i in 0..offsets.len() {
896-
let mut path = path.clone();
897-
self.dump_field_name(&mut path, dest.layout.ty, i, variant).unwrap();
898-
let field = self.mplace_field(dest, i as u64)?;
899-
self.validate_mplace(field, path, seen, todo)?;
900-
}
901-
// FIXME: For a TyStr, check that this is valid UTF-8.
902-
},
903-
}
904-
905-
Ok(())
906-
}
907-
}
908-
}
909-
910648
#[inline(always)]
911649
pub fn frame(&self) -> &Frame<'mir, 'tcx> {
912650
self.stack.last().expect("no call frames exist")
@@ -1041,72 +779,5 @@ impl<'a, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M
1041779
pub fn truncate(&self, value: u128, ty: TyLayout<'_>) -> u128 {
1042780
truncate(value, ty.size)
1043781
}
1044-
1045-
fn dump_field_name(&self, s: &mut String, ty: Ty<'tcx>, i: usize, variant: usize) -> ::std::fmt::Result {
1046-
match ty.sty {
1047-
ty::TyBool |
1048-
ty::TyChar |
1049-
ty::TyInt(_) |
1050-
ty::TyUint(_) |
1051-
ty::TyFloat(_) |
1052-
ty::TyFnPtr(_) |
1053-
ty::TyNever |
1054-
ty::TyFnDef(..) |
1055-
ty::TyGeneratorWitness(..) |
1056-
ty::TyForeign(..) |
1057-
ty::TyDynamic(..) => {
1058-
bug!("field_name({:?}): not applicable", ty)
1059-
}
1060-
1061-
// Potentially-fat pointers.
1062-
ty::TyRef(_, pointee, _) |
1063-
ty::TyRawPtr(ty::TypeAndMut { ty: pointee, .. }) => {
1064-
assert!(i < 2);
1065-
1066-
// Reuse the fat *T type as its own thin pointer data field.
1067-
// This provides information about e.g. DST struct pointees
1068-
// (which may have no non-DST form), and will work as long
1069-
// as the `Abi` or `FieldPlacement` is checked by users.
1070-
if i == 0 {
1071-
return write!(s, ".data_ptr");
1072-
}
1073-
1074-
match self.tcx.struct_tail(pointee).sty {
1075-
ty::TySlice(_) |
1076-
ty::TyStr => write!(s, ".len"),
1077-
ty::TyDynamic(..) => write!(s, ".vtable_ptr"),
1078-
_ => bug!("field_name({:?}): not applicable", ty)
1079-
}
1080-
}
1081-
1082-
// Arrays and slices.
1083-
ty::TyArray(_, _) |
1084-
ty::TySlice(_) |
1085-
ty::TyStr => write!(s, "[{}]", i),
1086-
1087-
// generators and closures.
1088-
ty::TyClosure(def_id, _) | ty::TyGenerator(def_id, _, _) => {
1089-
let node_id = self.tcx.hir.as_local_node_id(def_id).unwrap();
1090-
let freevar = self.tcx.with_freevars(node_id, |fv| fv[i]);
1091-
write!(s, ".upvar({})", self.tcx.hir.name(freevar.var_id()))
1092-
}
1093-
1094-
ty::TyTuple(_) => write!(s, ".{}", i),
1095-
1096-
// enums
1097-
ty::TyAdt(def, ..) if def.is_enum() => {
1098-
let variant = &def.variants[variant];
1099-
write!(s, ".{}::{}", variant.name, variant.fields[i].ident)
1100-
}
1101-
1102-
// other ADTs.
1103-
ty::TyAdt(def, _) => write!(s, ".{}", def.non_enum_variant().fields[i].ident),
1104-
1105-
ty::TyProjection(_) | ty::TyAnon(..) | ty::TyParam(_) |
1106-
ty::TyInfer(_) | ty::TyError => {
1107-
bug!("dump_field_name: unexpected type `{}`", ty)
1108-
}
1109-
}
1110-
}
1111782
}
1112783

src/librustc_mir/interpret/mod.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ mod step;
1111
mod terminator;
1212
mod traits;
1313
mod const_eval;
14+
mod validity;
1415

1516
pub use self::eval_context::{
1617
EvalContext, Frame, StackPopCleanup, LocalValue,

0 commit comments

Comments
 (0)