1 use rustc::hir::Mutability;
2 use rustc::mir::{self, ValidationOp};
3 use rustc::ty::{self, Ty};
4 use rustc::middle::region::CodeExtent;
6 use error::{EvalError, EvalResult};
7 use eval_context::{EvalContext};
8 use memory::AccessKind;
10 use lvalue::{Lvalue, LvalueExtra};
13 #[derive(Copy, Clone, Debug)]
14 pub struct ValidationCtx {
16 region: Option<CodeExtent>,
21 pub fn new(op: ValidationOp) -> Self {
23 op, region: None, mutbl: Mutability::MutMutable,
28 impl<'a, 'tcx> EvalContext<'a, 'tcx> {
33 variant: &ty::VariantDef,
34 subst: &ty::subst::Substs<'tcx>,
36 ) -> EvalResult<'tcx> {
37 // TODO: Take visibility/privacy into account.
38 for (idx, field) in variant.fields.iter().enumerate() {
39 let field_ty = field.ty(self.tcx, subst);
40 let field_lvalue = self.lvalue_field(lvalue, idx, ty, field_ty)?;
41 self.validate(field_lvalue, field_ty, vctx)?;
46 fn validate_ptr(&mut self, val: Value, pointee_ty: Ty<'tcx>, vctx: ValidationCtx) -> EvalResult<'tcx> {
47 // Check alignment and non-NULLness
48 let (_, align) = self.size_and_align_of_dst(pointee_ty, val)?;
49 let ptr = val.into_ptr(&mut self.memory)?;
50 self.memory.check_align(ptr, align)?;
53 let pointee_lvalue = self.val_to_lvalue(val, pointee_ty)?;
54 self.validate(pointee_lvalue, pointee_ty, vctx)
57 /// Validate the lvalue at the given type. If `release` is true, just do a release of all write locks
58 pub(super) fn validate(&mut self, lvalue: Lvalue<'tcx>, ty: Ty<'tcx>, mut vctx: ValidationCtx) -> EvalResult<'tcx>
60 use rustc::ty::TypeVariants::*;
61 use rustc::ty::RegionKind::*;
62 use rustc::ty::AdtKind;
63 use self::Mutability::*;
64 trace!("Validating {:?} at type {}, context {:?}", lvalue, ty, vctx);
66 // Decide whether this type *owns* the memory it covers (like integers), or whether it
67 // just assembles pieces (that each own their memory) together to a larger whole.
68 // TODO: Currently, we don't acquire locks for padding and discriminants. We should.
69 let is_owning = match ty.sty {
70 TyInt(_) | TyUint(_) | TyRawPtr(_) |
71 TyBool | TyFloat(_) | TyChar | TyStr |
72 TyRef(..) | TyFnPtr(..) | TyNever => true,
73 TyAdt(adt, _) if adt.is_box() => true,
74 TySlice(_) | TyAdt(_, _) | TyTuple(..) | TyClosure(..) | TyArray(..) | TyDynamic(..) => false,
75 TyParam(_) | TyInfer(_) => bug!("I got an incomplete type for validation"),
76 _ => return Err(EvalError::Unimplemented(format!("Unimplemented type encountered when checking validity."))),
80 Lvalue::Ptr { ptr, extra, aligned: _ } => {
82 // FIXME: Can we reuse size_and_align_of_dst for Lvalues?
83 let len = match self.type_size(ty)? {
85 assert_eq!(extra, LvalueExtra::None, "Got a fat ptr to a sized type");
89 // The only unsized typ we concider "owning" is TyStr.
90 assert_eq!(ty.sty, TyStr, "Found a surprising unsized owning type");
91 // The extra must be the length, in bytes.
93 LvalueExtra::Length(len) => len,
94 _ => bug!("TyStr must have a length as extra"),
100 let ptr = ptr.to_ptr()?;
101 let access = match vctx.mutbl { MutMutable => AccessKind::Write, MutImmutable => AccessKind::Read };
103 ValidationOp::Acquire => self.memory.acquire_lock(ptr, len, vctx.region, access)?,
104 ValidationOp::Release => self.memory.release_write_lock_until(ptr, len, None)?,
105 ValidationOp::Suspend(region) => self.memory.release_write_lock_until(ptr, len, Some(region))?,
109 Lvalue::Local { .. } | Lvalue::Global(..) => {
110 // These are not backed by memory, so we have nothing to do.
116 TyInt(_) | TyUint(_) | TyRawPtr(_) => {
117 // TODO: Make sure these are not undef.
118 // 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.
121 TyBool | TyFloat(_) | TyChar | TyStr => {
122 // TODO: Check if these are valid bool/float/codepoint/UTF-8, respectively (and in particular, not undef).
126 Err(EvalError::ValidationFailure(format!("The empty type is never valid.")))
128 TyRef(region, ty::TypeAndMut { ty: pointee_ty, mutbl }) => {
129 let val = self.read_lvalue(lvalue)?;
130 // Sharing restricts our context
131 if mutbl == MutImmutable {
132 // Actually, in case of releasing-validation, this means we are done.
133 if vctx.op != ValidationOp::Acquire {
136 vctx.mutbl = MutImmutable;
138 // Inner lifetimes *outlive* outer ones, so only if we have no lifetime restriction yet,
139 // we record the region of this borrow to the context.
140 if vctx.region == None {
142 ReScope(ce) => vctx.region = Some(ce),
143 // It is possible for us to encode erased lifetimes here because the lifetimes in
144 // this functions' Subst will be erased.
148 self.validate_ptr(val, pointee_ty, vctx)
150 TyAdt(adt, _) if adt.is_box() => {
151 let val = self.read_lvalue(lvalue)?;
152 self.validate_ptr(val, ty.boxed_ty(), vctx)
155 // TODO: The function names here could need some improvement.
156 let ptr = self.read_lvalue(lvalue)?.into_ptr(&mut self.memory)?.to_ptr()?;
157 self.memory.get_fn(ptr)?;
158 // TODO: Check if the signature matches (should be the same check as what terminator/mod.rs already does on call?).
163 TySlice(elem_ty) => {
164 let len = match lvalue {
165 Lvalue::Ptr { extra: LvalueExtra::Length(len), .. } => len,
166 _ => bug!("acquire_valid of a TySlice given non-slice lvalue: {:?}", lvalue),
169 let inner_lvalue = self.lvalue_index(lvalue, ty, i)?;
170 self.validate(inner_lvalue, elem_ty, vctx)?;
174 TyArray(elem_ty, len) => {
176 let inner_lvalue = self.lvalue_index(lvalue, ty, i as u64)?;
177 self.validate(inner_lvalue, elem_ty, vctx)?;
181 TyDynamic(_data, _region) => {
182 // Check that this is a valid vtable
183 let vtable = match lvalue {
184 Lvalue::Ptr { extra: LvalueExtra::Vtable(vtable), .. } => vtable,
185 _ => bug!("acquire_valid of a TyDynamic given non-trait-object lvalue: {:?}", lvalue),
187 self.read_size_and_align_from_vtable(vtable)?;
188 // TODO: Check that the vtable contains all the function pointers we expect it to have.
189 // TODO: Is there anything we can/should validate here? Trait objects cannot have any operations performed
190 // on them directly. We cannot, in general, even acquire any locks as the trait object *could*
191 // contain an UnsafeCell. If we call functions to get access to data, we will validate
192 // their return values. So, it doesn't seem like there's anything to do.
195 TyAdt(adt, subst) => {
196 if Some(adt.did) == self.tcx.lang_items.unsafe_cell_type() {
197 // No locks for unsafe cells. Also no other validation, the only field is private anyway.
201 match adt.adt_kind() {
203 // TODO: Can we get the discriminant without forcing an allocation?
204 let ptr = self.force_allocation(lvalue)?.to_ptr()?;
205 let discr = self.read_discriminant_value(ptr, ty)?;
207 // Get variant index for discriminant
208 let variant_idx = adt.discriminants(self.tcx)
209 .position(|variant_discr| variant_discr.to_u128_unchecked() == discr)
210 .ok_or(EvalError::InvalidDiscriminant)?;
211 let variant = &adt.variants[variant_idx];
213 if variant.fields.len() > 0 {
214 // Downcast to this variant, if needed
215 let lvalue = if adt.variants.len() > 1 {
216 self.eval_lvalue_projection(lvalue, ty, &mir::ProjectionElem::Downcast(adt, variant_idx))?
221 // Recursively validate the fields
222 self.validate_variant(lvalue, ty, variant, subst, vctx)
224 // No fields, nothing left to check. Downcasting may fail, e.g. in case of a CEnum.
229 self.validate_variant(lvalue, ty, adt.struct_variant(), subst, vctx)
232 // No guarantees are provided for union types.
233 // TODO: Make sure that all access to union fields is unsafe; otherwise, we may have some checking to do (but what exactly?)
238 TyTuple(ref types, _) => {
239 for (idx, field_ty) in types.iter().enumerate() {
240 let field_lvalue = self.lvalue_field(lvalue, idx, ty, field_ty)?;
241 self.validate(field_lvalue, field_ty, vctx)?;
245 TyClosure(def_id, ref closure_substs) => {
246 for (idx, field_ty) in closure_substs.upvar_tys(def_id, self.tcx).enumerate() {
247 let field_lvalue = self.lvalue_field(lvalue, idx, ty, field_ty)?;
248 self.validate(field_lvalue, field_ty, vctx)?;
250 // TODO: Check if the signature matches (should be the same check as what terminator/mod.rs already does on call?).
251 // Is there other things we can/should check? Like vtable pointers?
254 _ => bug!("We already establishd that this is a type we support.")