]> git.lizzy.rs Git - rust.git/blob - miri/helpers.rs
3ee148afb2b22649424c3c6d866b755216a97eb5
[rust.git] / miri / helpers.rs
1 use rustc::mir::interpret::{Pointer, EvalResult, PrimVal, EvalContext};
2
3 use rustc::ty::Ty;
4
5 pub trait EvalContextExt<'tcx> {
6     fn wrapping_pointer_offset(
7         &self,
8         ptr: Pointer,
9         pointee_ty: Ty<'tcx>,
10         offset: i64,
11     ) -> EvalResult<'tcx, Pointer>;
12
13     fn pointer_offset(
14         &self,
15         ptr: Pointer,
16         pointee_ty: Ty<'tcx>,
17         offset: i64,
18     ) -> EvalResult<'tcx, Pointer>;
19 }
20
21 impl<'a, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'tcx, super::Evaluator> {
22     fn wrapping_pointer_offset(
23         &self,
24         ptr: Pointer,
25         pointee_ty: Ty<'tcx>,
26         offset: i64,
27     ) -> EvalResult<'tcx, Pointer> {
28         // FIXME: assuming here that type size is < i64::max_value()
29         let pointee_size = self.type_size(pointee_ty)?.expect(
30             "cannot offset a pointer to an unsized type",
31         ) as i64;
32         let offset = offset.overflowing_mul(pointee_size).0;
33         ptr.wrapping_signed_offset(offset, self)
34     }
35
36     fn pointer_offset(
37         &self,
38         ptr: Pointer,
39         pointee_ty: Ty<'tcx>,
40         offset: i64,
41     ) -> EvalResult<'tcx, Pointer> {
42         // This function raises an error if the offset moves the pointer outside of its allocation.  We consider
43         // ZSTs their own huge allocation that doesn't overlap with anything (and nothing moves in there because the size is 0).
44         // We also consider the NULL pointer its own separate allocation, and all the remaining integers pointers their own
45         // allocation.
46
47         if ptr.is_null()? {
48             // NULL pointers must only be offset by 0
49             return if offset == 0 {
50                 Ok(ptr)
51             } else {
52                 err!(InvalidNullPointerUsage)
53             };
54         }
55         // FIXME: assuming here that type size is < i64::max_value()
56         let pointee_size = self.type_size(pointee_ty)?.expect(
57             "cannot offset a pointer to an unsized type",
58         ) as i64;
59         return if let Some(offset) = offset.checked_mul(pointee_size) {
60             let ptr = ptr.signed_offset(offset, self)?;
61             // Do not do bounds-checking for integers; they can never alias a normal pointer anyway.
62             if let PrimVal::Ptr(ptr) = ptr.into_inner_primval() {
63                 self.memory.check_bounds(ptr, false)?;
64             } else if ptr.is_null()? {
65                 // We moved *to* a NULL pointer.  That seems wrong, LLVM considers the NULL pointer its own small allocation.  Reject this, for now.
66                 return err!(InvalidNullPointerUsage);
67             }
68             Ok(ptr)
69         } else {
70             err!(OverflowingMath)
71         };
72     }
73 }