]> git.lizzy.rs Git - rust.git/blob - src/librustc_mir/interpret/validation.rs
handle type of function definitions (98)
[rust.git] / src / librustc_mir / interpret / validation.rs
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;
7
8 use error::{EvalError, EvalResult};
9 use eval_context::{EvalContext};
10 use memory::AccessKind;
11 use value::Value;
12 use lvalue::{Lvalue, LvalueExtra};
13
14 // Validity checks
15 #[derive(Copy, Clone, Debug)]
16 pub struct ValidationCtx {
17     op: ValidationOp,
18     region: Option<CodeExtent>,
19     mutbl: Mutability,
20 }
21
22 impl ValidationCtx {
23     pub fn new(op: ValidationOp) -> Self {
24         ValidationCtx {
25             op, region: None, mutbl: Mutability::MutMutable,
26         }
27     }
28 }
29
30 impl<'a, 'tcx> EvalContext<'a, 'tcx> {
31     fn validate_variant(
32         &mut self,
33         lvalue: Lvalue<'tcx>,
34         ty: Ty<'tcx>,
35         variant: &ty::VariantDef,
36         subst: &ty::subst::Substs<'tcx>,
37         vctx: ValidationCtx,
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)?;
44         }
45         Ok(())
46     }
47
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)?;
53
54         // Recurse
55         let pointee_lvalue = self.val_to_lvalue(val, pointee_ty)?;
56         self.validate(pointee_lvalue, pointee_ty, vctx)
57     }
58
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>
61     {
62         use rustc::ty::TypeVariants::*;
63         use rustc::ty::RegionKind::*;
64         use rustc::ty::AdtKind;
65         use self::Mutability::*;
66
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)
72             })
73         }
74         let ty = ty; // no more mutation
75         trace!("Validating {:?} at type {}, context {:?}", lvalue, ty, vctx);
76
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"),
87         };
88         if is_owning {
89             match lvalue {
90                 Lvalue::Ptr { ptr, extra, aligned: _ } => {
91                     // Determine the size
92                     // FIXME: Can we reuse size_and_align_of_dst for Lvalues?
93                     let len = match self.type_size(ty)? {
94                         Some(size) => {
95                             assert_eq!(extra, LvalueExtra::None, "Got a fat ptr to a sized type");
96                             size
97                         }
98                         None => {
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.
102                             match extra {
103                                 LvalueExtra::Length(len) => len,
104                                 _ => bug!("TyStr must have a length as extra"),
105                             }
106                         }
107                     };
108                     // Handle locking
109                     if len > 0 {
110                         let ptr = ptr.to_ptr()?;
111                         let access = match vctx.mutbl { MutMutable => AccessKind::Write, MutImmutable => AccessKind::Read };
112                         match vctx.op {
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))?,
116                         }
117                     }
118                 }
119                 Lvalue::Local { .. } | Lvalue::Global(..) => {
120                     // These are not backed by memory, so we have nothing to do.
121                 }
122             }
123         }
124
125         match ty.sty {
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.
129                 Ok(())
130             }
131             TyBool | TyFloat(_) | TyChar | TyStr => {
132                 // TODO: Check if these are valid bool/float/codepoint/UTF-8, respectively (and in particular, not undef).
133                 Ok(())
134             }
135             TyNever => {
136                 Err(EvalError::ValidationFailure(format!("The empty type is never valid.")))
137             }
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 {
144                         return Ok(());
145                     }
146                     vctx.mutbl = MutImmutable;
147                 }
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 {
151                     match *region {
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.
155                         _ => {},
156                     }
157                 }
158                 self.validate_ptr(val, pointee_ty, vctx)
159             }
160             TyAdt(adt, _) if adt.is_box() => {
161                 let val = self.read_lvalue(lvalue)?;
162                 self.validate_ptr(val, ty.boxed_ty(), vctx)
163             }
164             TyFnPtr(_sig) => {
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?).
168                 Ok(())
169             }
170             TyFnDef(..) => {
171                 // This is a zero-sized type with all relevant data sitting in the type.
172                 // There is nothing to validate.
173                 Ok(())
174             }
175
176             // Compound types
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),
181                 };
182                 for i in 0..len {
183                     let inner_lvalue = self.lvalue_index(lvalue, ty, i)?;
184                     self.validate(inner_lvalue, elem_ty, vctx)?;
185                 }
186                 Ok(())
187             }
188             TyArray(elem_ty, len) => {
189                 for i in 0..len {
190                     let inner_lvalue = self.lvalue_index(lvalue, ty, i as u64)?;
191                     self.validate(inner_lvalue, elem_ty, vctx)?;
192                 }
193                 Ok(())
194             }
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),
200                 };
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.
207                 Ok(())
208             }
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.
212                     return Ok(());
213                 }
214
215                 match adt.adt_kind() {
216                     AdtKind::Enum => {
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)?;
220
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];
226
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))?
231                             } else {
232                                 lvalue
233                             };
234
235                             // Recursively validate the fields
236                             self.validate_variant(lvalue, ty, variant, subst, vctx)
237                         } else {
238                             // No fields, nothing left to check.  Downcasting may fail, e.g. in case of a CEnum.
239                             Ok(())
240                         }
241                     }
242                     AdtKind::Struct => {
243                         self.validate_variant(lvalue, ty, adt.struct_variant(), subst, vctx)
244                     }
245                     AdtKind::Union => {
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?)
248                         Ok(())
249                     }
250                 }
251             }
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)?;
256                 }
257                 Ok(())
258             }
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)?;
263                 }
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?
266                 Ok(())
267             }
268             _ => bug!("We already establishd that this is a type we support.")
269         }
270     }
271 }