1 use rustc::hir::Mutability;
2 use rustc::mir::{self, ValidationOp};
3 use rustc::ty::{self, Ty, TypeFoldable};
4 use rustc::traits::Reveal;
5 use rustc::infer::TransNormalize;
6 use rustc::middle::region::CodeExtent;
8 use error::{EvalError, EvalResult};
9 use eval_context::{EvalContext};
10 use memory::AccessKind;
12 use lvalue::{Lvalue, LvalueExtra};
15 #[derive(Copy, Clone, Debug)]
16 pub struct ValidationCtx {
18 region: Option<CodeExtent>,
23 pub fn new(op: ValidationOp) -> Self {
25 op, region: None, mutbl: Mutability::MutMutable,
30 impl<'a, 'tcx> EvalContext<'a, 'tcx> {
35 variant: &ty::VariantDef,
36 subst: &ty::subst::Substs<'tcx>,
38 ) -> EvalResult<'tcx> {
39 // TODO: Take visibility/privacy into account.
40 for (idx, field) in variant.fields.iter().enumerate() {
41 let field_ty = field.ty(self.tcx, subst);
42 let field_lvalue = self.lvalue_field(lvalue, idx, ty, field_ty)?;
43 self.validate(field_lvalue, field_ty, vctx)?;
48 fn validate_ptr(&mut self, val: Value, pointee_ty: Ty<'tcx>, vctx: ValidationCtx) -> EvalResult<'tcx> {
49 // Check alignment and non-NULLness
50 let (_, align) = self.size_and_align_of_dst(pointee_ty, val)?;
51 let ptr = val.into_ptr(&mut self.memory)?;
52 self.memory.check_align(ptr, align)?;
55 let pointee_lvalue = self.val_to_lvalue(val, pointee_ty)?;
56 self.validate(pointee_lvalue, pointee_ty, vctx)
59 /// Validate the lvalue at the given type. If `release` is true, just do a release of all write locks
60 pub(super) fn validate(&mut self, lvalue: Lvalue<'tcx>, mut ty: Ty<'tcx>, mut vctx: ValidationCtx) -> EvalResult<'tcx>
62 use rustc::ty::TypeVariants::*;
63 use rustc::ty::RegionKind::*;
64 use rustc::ty::AdtKind;
65 use self::Mutability::*;
67 // This is essentially a copy of normalize_associated_type, but without erasure
68 if ty.has_projection_types() {
69 let param_env = ty::ParamEnv::empty(Reveal::All);
70 ty = self.tcx.infer_ctxt().enter(move |infcx| {
71 ty.trans_normalize(&infcx, param_env)
74 let ty = ty; // no more mutation
75 trace!("Validating {:?} at type {}, context {:?}", lvalue, ty, vctx);
77 // Decide whether this type *owns* the memory it covers (like integers), or whether it
78 // just assembles pieces (that each own their memory) together to a larger whole.
79 // TODO: Currently, we don't acquire locks for padding and discriminants. We should.
80 let is_owning = match ty.sty {
81 TyInt(_) | TyUint(_) | TyRawPtr(_) |
82 TyBool | TyFloat(_) | TyChar | TyStr |
83 TyRef(..) | TyFnPtr(..) | TyFnDef(..) | TyNever => true,
84 TyAdt(adt, _) if adt.is_box() => true,
85 TySlice(_) | TyAdt(_, _) | TyTuple(..) | TyClosure(..) | TyArray(..) | TyDynamic(..) => false,
86 TyParam(_) | TyInfer(_) | TyProjection(_) | TyAnon(..) | TyError => bug!("I got an incomplete/unnormalized type for validation"),
90 Lvalue::Ptr { ptr, extra, aligned: _ } => {
92 // FIXME: Can we reuse size_and_align_of_dst for Lvalues?
93 let len = match self.type_size(ty)? {
95 assert_eq!(extra, LvalueExtra::None, "Got a fat ptr to a sized type");
99 // The only unsized typ we concider "owning" is TyStr.
100 assert_eq!(ty.sty, TyStr, "Found a surprising unsized owning type");
101 // The extra must be the length, in bytes.
103 LvalueExtra::Length(len) => len,
104 _ => bug!("TyStr must have a length as extra"),
110 let ptr = ptr.to_ptr()?;
111 let access = match vctx.mutbl { MutMutable => AccessKind::Write, MutImmutable => AccessKind::Read };
113 ValidationOp::Acquire => self.memory.acquire_lock(ptr, len, vctx.region, access)?,
114 ValidationOp::Release => self.memory.release_write_lock_until(ptr, len, None)?,
115 ValidationOp::Suspend(region) => self.memory.release_write_lock_until(ptr, len, Some(region))?,
119 Lvalue::Local { .. } | Lvalue::Global(..) => {
120 // These are not backed by memory, so we have nothing to do.
126 TyInt(_) | TyUint(_) | TyRawPtr(_) => {
127 // TODO: Make sure these are not undef.
128 // 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.
131 TyBool | TyFloat(_) | TyChar | TyStr => {
132 // TODO: Check if these are valid bool/float/codepoint/UTF-8, respectively (and in particular, not undef).
136 Err(EvalError::ValidationFailure(format!("The empty type is never valid.")))
138 TyRef(region, ty::TypeAndMut { ty: pointee_ty, mutbl }) => {
139 let val = self.read_lvalue(lvalue)?;
140 // Sharing restricts our context
141 if mutbl == MutImmutable {
142 // Actually, in case of releasing-validation, this means we are done.
143 if vctx.op != ValidationOp::Acquire {
146 vctx.mutbl = MutImmutable;
148 // Inner lifetimes *outlive* outer ones, so only if we have no lifetime restriction yet,
149 // we record the region of this borrow to the context.
150 if vctx.region == None {
152 ReScope(ce) => vctx.region = Some(ce),
153 // It is possible for us to encode erased lifetimes here because the lifetimes in
154 // this functions' Subst will be erased.
158 self.validate_ptr(val, pointee_ty, vctx)
160 TyAdt(adt, _) if adt.is_box() => {
161 let val = self.read_lvalue(lvalue)?;
162 self.validate_ptr(val, ty.boxed_ty(), vctx)
165 let ptr = self.read_lvalue(lvalue)?.into_ptr(&mut self.memory)?.to_ptr()?;
166 self.memory.get_fn(ptr)?;
167 // TODO: Check if the signature matches (should be the same check as what terminator/mod.rs already does on call?).
171 // This is a zero-sized type with all relevant data sitting in the type.
172 // There is nothing to validate.
177 TySlice(elem_ty) => {
178 let len = match lvalue {
179 Lvalue::Ptr { extra: LvalueExtra::Length(len), .. } => len,
180 _ => bug!("acquire_valid of a TySlice given non-slice lvalue: {:?}", lvalue),
183 let inner_lvalue = self.lvalue_index(lvalue, ty, i)?;
184 self.validate(inner_lvalue, elem_ty, vctx)?;
188 TyArray(elem_ty, len) => {
190 let inner_lvalue = self.lvalue_index(lvalue, ty, i as u64)?;
191 self.validate(inner_lvalue, elem_ty, vctx)?;
195 TyDynamic(_data, _region) => {
196 // Check that this is a valid vtable
197 let vtable = match lvalue {
198 Lvalue::Ptr { extra: LvalueExtra::Vtable(vtable), .. } => vtable,
199 _ => bug!("acquire_valid of a TyDynamic given non-trait-object lvalue: {:?}", lvalue),
201 self.read_size_and_align_from_vtable(vtable)?;
202 // TODO: Check that the vtable contains all the function pointers we expect it to have.
203 // TODO: Is there anything we can/should validate here? Trait objects cannot have any operations performed
204 // on them directly. We cannot, in general, even acquire any locks as the trait object *could*
205 // contain an UnsafeCell. If we call functions to get access to data, we will validate
206 // their return values. So, it doesn't seem like there's anything to do.
209 TyAdt(adt, subst) => {
210 if Some(adt.did) == self.tcx.lang_items.unsafe_cell_type() {
211 // No locks for unsafe cells. Also no other validation, the only field is private anyway.
215 match adt.adt_kind() {
217 // TODO: Can we get the discriminant without forcing an allocation?
218 let ptr = self.force_allocation(lvalue)?.to_ptr()?;
219 let discr = self.read_discriminant_value(ptr, ty)?;
221 // Get variant index for discriminant
222 let variant_idx = adt.discriminants(self.tcx)
223 .position(|variant_discr| variant_discr.to_u128_unchecked() == discr)
224 .ok_or(EvalError::InvalidDiscriminant)?;
225 let variant = &adt.variants[variant_idx];
227 if variant.fields.len() > 0 {
228 // Downcast to this variant, if needed
229 let lvalue = if adt.variants.len() > 1 {
230 self.eval_lvalue_projection(lvalue, ty, &mir::ProjectionElem::Downcast(adt, variant_idx))?
235 // Recursively validate the fields
236 self.validate_variant(lvalue, ty, variant, subst, vctx)
238 // No fields, nothing left to check. Downcasting may fail, e.g. in case of a CEnum.
243 self.validate_variant(lvalue, ty, adt.struct_variant(), subst, vctx)
246 // No guarantees are provided for union types.
247 // TODO: Make sure that all access to union fields is unsafe; otherwise, we may have some checking to do (but what exactly?)
252 TyTuple(ref types, _) => {
253 for (idx, field_ty) in types.iter().enumerate() {
254 let field_lvalue = self.lvalue_field(lvalue, idx, ty, field_ty)?;
255 self.validate(field_lvalue, field_ty, vctx)?;
259 TyClosure(def_id, ref closure_substs) => {
260 for (idx, field_ty) in closure_substs.upvar_tys(def_id, self.tcx).enumerate() {
261 let field_lvalue = self.lvalue_field(lvalue, idx, ty, field_ty)?;
262 self.validate(field_lvalue, field_ty, vctx)?;
264 // TODO: Check if the signature matches (should be the same check as what terminator/mod.rs already does on call?).
265 // Is there other things we can/should check? Like vtable pointers?
268 _ => bug!("We already establishd that this is a type we support.")