]> git.lizzy.rs Git - rust.git/commitdiff
make sure ByVal pointers act just like ByRef to a pointer
authorOliver Schneider <git-spam-no-reply9815368754983@oli-obk.de>
Tue, 15 Nov 2016 13:12:49 +0000 (14:12 +0100)
committerOliver Schneider <git-spam-no-reply9815368754983@oli-obk.de>
Tue, 15 Nov 2016 13:12:49 +0000 (14:12 +0100)
src/interpreter/cast.rs
src/interpreter/mod.rs
src/interpreter/terminator/intrinsics.rs
src/interpreter/terminator/mod.rs
src/interpreter/value.rs
src/memory.rs
src/primval.rs
tests/compile-fail/cast_int_to_fn_ptr.rs [new file with mode: 0644]

index e59376c32135756de9b11ec1ad7f43220434be4d..217a10a4c7bccb60d8fd53d49d3cceafddc49d26 100644 (file)
@@ -21,10 +21,7 @@ pub(super) fn cast_primval(&self, val: PrimVal, ty: Ty<'tcx>) -> EvalResult<'tcx
 
             Bool | Char | U8 | U16 | U32 | U64 => self.cast_int(val.bits, ty, false),
 
-            FnPtr | Ptr => {
-                let ptr = val.expect_ptr("FnPtr- or Ptr-tagged PrimVal had no relocation");
-                self.cast_ptr(ptr, ty)
-            }
+            FnPtr | Ptr => self.cast_ptr(val.to_ptr(), ty),
         }
     }
 
index a67142e7335d2b54625d9297c320205b10e80d36..791466f6908bfe402c2d7474eeb37b095ce466c6 100644 (file)
@@ -963,33 +963,27 @@ fn eval_lvalue_projection(
             }
 
             Deref => {
-                use interpreter::value::Value::*;
+                let val = self.eval_and_read_lvalue(&proj.base)?;
 
-                let val = match self.eval_and_read_lvalue(&proj.base)? {
-                    ByRef(ptr) => self.read_value(ptr, base_ty)?,
-                    v => v,
+                let pointee_type = match base_ty.sty {
+                    ty::TyRawPtr(ty::TypeAndMut{ty, ..}) |
+                    ty::TyRef(_, ty::TypeAndMut{ty, ..}) |
+                    ty::TyBox(ty) => ty,
+                    _ => bug!("can only deref pointer types"),
                 };
 
-                match val {
-                    ByValPair(ptr, vtable)
-                        if ptr.try_as_ptr().is_some() && vtable.try_as_ptr().is_some()
-                    => {
-                        let ptr = ptr.try_as_ptr().unwrap();
-                        let vtable = vtable.try_as_ptr().unwrap();
-                        (ptr, LvalueExtra::Vtable(vtable))
-                    }
-
-                    ByValPair(ptr, n) if ptr.try_as_ptr().is_some() => {
-                        let ptr = ptr.try_as_ptr().unwrap();
-                        (ptr, LvalueExtra::Length(n.expect_uint("slice length")))
-                    }
+                trace!("deref to {} on {:?}", pointee_type, val);
 
-                    ByVal(ptr) if ptr.try_as_ptr().is_some() => {
-                        let ptr = ptr.try_as_ptr().unwrap();
-                        (ptr, LvalueExtra::None)
-                    }
-
-                    _ => bug!("can't deref non pointer types"),
+                match self.tcx.struct_tail(pointee_type).sty {
+                    ty::TyTrait(_) => {
+                        let (ptr, vtable) = val.expect_ptr_vtable_pair(&self.memory)?;
+                        (ptr, LvalueExtra::Vtable(vtable))
+                    },
+                    ty::TyStr | ty::TySlice(_) => {
+                        let (ptr, len) = val.expect_slice(&self.memory)?;
+                        (ptr, LvalueExtra::Length(len))
+                    },
+                    _ => (val.read_ptr(&self.memory)?, LvalueExtra::None),
                 }
             }
 
index 280cabc07859365e07cf17da0722b0d2dc8266f0..bc258574665d1e870615f7b750a09efc490f787e 100644 (file)
@@ -124,15 +124,17 @@ pub(super) fn call_intrinsic(
 
             "drop_in_place" => {
                 let ty = substs.type_at(0);
+                trace!("drop in place on {}", ty);
                 let ptr_ty = self.tcx.mk_mut_ptr(ty);
                 let lvalue = match self.follow_by_ref_value(arg_vals[0], ptr_ty)? {
                     Value::ByRef(_) => bug!("follow_by_ref_value returned ByRef"),
-                    Value::ByVal(ptr) => Lvalue::from_ptr(ptr.expect_ptr("drop_in_place first arg not a pointer")),
+                    Value::ByVal(value) => Lvalue::from_ptr(value.to_ptr()),
                     Value::ByValPair(ptr, extra) => Lvalue::Ptr {
-                        ptr: ptr.expect_ptr("drop_in_place first arg not a pointer"),
-                        extra: match extra.try_as_ptr() {
-                            Some(vtable) => LvalueExtra::Vtable(vtable),
-                            None => LvalueExtra::Length(extra.expect_uint("either pointer or not, but not neither")),
+                        ptr: ptr.to_ptr(),
+                        extra: match self.tcx.struct_tail(ty).sty {
+                            ty::TyTrait(_) => LvalueExtra::Vtable(extra.to_ptr()),
+                            ty::TyStr | ty::TySlice(_) => LvalueExtra::Length(extra.try_as_uint()?),
+                            _ => bug!("invalid fat pointer type: {}", ptr_ty),
                         },
                     },
                 };
@@ -440,7 +442,7 @@ fn size_and_align_of_dst(
                 ty::TySlice(_) | ty::TyStr => {
                     let elem_ty = ty.sequence_element_type(self.tcx);
                     let elem_size = self.type_size(elem_ty).expect("slice element must be sized") as u64;
-                    let len = value.expect_slice_len(&self.memory)?;
+                    let (_, len) = value.expect_slice(&self.memory)?;
                     let align = self.type_align(elem_ty);
                     Ok((len * elem_size, align as u64))
                 }
index 655a59902e9ee3ddd4f50e50365bf9e2f820436e..fbd9e76a07f2418cdbe02eb24c51830c655cf4ae 100644 (file)
@@ -85,8 +85,7 @@ pub(super) fn eval_terminator(
                 let func_ty = self.operand_ty(func);
                 match func_ty.sty {
                     ty::TyFnPtr(bare_fn_ty) => {
-                        let fn_ptr = self.eval_operand_to_primval(func)?
-                            .expect_fn_ptr("TyFnPtr callee did not evaluate to FnPtr");
+                        let fn_ptr = self.eval_operand_to_primval(func)?.to_ptr();
                         let (def_id, substs, fn_ty) = self.memory.get_fn(fn_ptr.alloc_id)?;
                         if fn_ty != bare_fn_ty {
                             return Err(EvalError::FunctionPointerTyMismatch(fn_ty, bare_fn_ty));
@@ -542,14 +541,15 @@ fn drop(
                     Value::ByRef(_) => bug!("follow_by_ref_value can't result in ByRef"),
                     Value::ByVal(ptr) => {
                         assert!(self.type_is_sized(contents_ty));
-                        let contents_ptr = ptr.expect_ptr("value of Box type must be a pointer");
+                        let contents_ptr = ptr.to_ptr();
                         self.drop(Lvalue::from_ptr(contents_ptr), contents_ty, drop)?;
                     },
                     Value::ByValPair(prim_ptr, extra) => {
-                        let ptr = prim_ptr.expect_ptr("value of Box type must be a pointer");
-                        let extra = match extra.try_as_ptr() {
-                            Some(vtable) => LvalueExtra::Vtable(vtable),
-                            None => LvalueExtra::Length(extra.expect_uint("slice length")),
+                        let ptr = prim_ptr.to_ptr();
+                        let extra = match self.tcx.struct_tail(contents_ty).sty {
+                            ty::TyTrait(_) => LvalueExtra::Vtable(extra.to_ptr()),
+                            ty::TyStr | ty::TySlice(_) => LvalueExtra::Length(extra.try_as_uint()?),
+                            _ => bug!("invalid fat pointer type: {}", ty),
                         };
                         self.drop(
                             Lvalue::Ptr {
index d9285a41e41ab545d38105fce596da952d01ab98..fa89d02ad77d12dc151cff4248a99c5813d307bc 100644 (file)
@@ -22,10 +22,7 @@ pub(super) fn read_ptr(&self, mem: &Memory<'a, 'tcx>) -> EvalResult<'tcx, Pointe
         use self::Value::*;
         match *self {
             ByRef(ptr) => mem.read_ptr(ptr),
-
-            ByVal(ptr) | ByValPair(ptr, _) => {
-                Ok(ptr.try_as_ptr().expect("unimplemented: `read_ptr` on non-ptr primval"))
-            }
+            ByVal(ptr) | ByValPair(ptr, _) => Ok(ptr.to_ptr()),
         }
     }
 
@@ -35,29 +32,29 @@ pub(super) fn expect_ptr_vtable_pair(
     ) -> EvalResult<'tcx, (Pointer, Pointer)> {
         use self::Value::*;
         match *self {
-            ByRef(ptr) => {
-                let ptr = mem.read_ptr(ptr)?;
-                let vtable = mem.read_ptr(ptr.offset(mem.pointer_size() as isize))?;
+            ByRef(ref_ptr) => {
+                let ptr = mem.read_ptr(ref_ptr)?;
+                let vtable = mem.read_ptr(ref_ptr.offset(mem.pointer_size() as isize))?;
                 Ok((ptr, vtable))
             }
 
-            ByValPair(ptr, vtable)
-                if ptr.try_as_ptr().is_some() && vtable.try_as_ptr().is_some()
-            => {
-                let ptr = ptr.try_as_ptr().unwrap();
-                let vtable = vtable.try_as_ptr().unwrap();
-                Ok((ptr, vtable))
-            }
+            ByValPair(ptr, vtable) => Ok((ptr.to_ptr(), vtable.to_ptr())),
 
             _ => bug!("expected ptr and vtable, got {:?}", self),
         }
     }
 
-    pub(super) fn expect_slice_len(&self, mem: &Memory<'a, 'tcx>) -> EvalResult<'tcx, u64> {
+    pub(super) fn expect_slice(&self, mem: &Memory<'a, 'tcx>) -> EvalResult<'tcx, (Pointer, u64)> {
         use self::Value::*;
         match *self {
-            ByRef(ptr) => mem.read_usize(ptr.offset(mem.pointer_size() as isize)),
-            ByValPair(_, val) if val.kind.is_int() => Ok(val.bits),
+            ByRef(ref_ptr) => {
+                let ptr = mem.read_ptr(ref_ptr)?;
+                let len = mem.read_usize(ref_ptr.offset(mem.pointer_size() as isize))?;
+                Ok((ptr, len))
+            },
+            ByValPair(ptr, val) => {
+                Ok((ptr.to_ptr(), val.try_as_uint()?))
+            },
             _ => unimplemented!(),
         }
     }
index 412eb62e9aefe92aa253c755b0030f64edd7a93f..348437f50b6460e232b246afa17804225d4f60d2 100644 (file)
@@ -533,8 +533,8 @@ pub fn write_ptr(&mut self, dest: Pointer, ptr: Pointer) -> EvalResult<'tcx, ()>
     }
 
     pub fn write_primval(&mut self, dest: Pointer, val: PrimVal) -> EvalResult<'tcx, ()> {
-        if let Some(ptr) = val.try_as_ptr() {
-            return self.write_ptr(dest, ptr);
+        if let Some(alloc_id) = val.relocation {
+            return self.write_ptr(dest, Pointer::new(alloc_id, val.bits as usize));
         }
 
         use primval::PrimValKind::*;
index 2d8b50076234f46bc142d9e8747f68c8e5ee17aa..15cc88ca4cf9ec53d3fb93fafb9b8462842349a2 100644 (file)
@@ -137,15 +137,19 @@ pub fn to_f64(self) -> f64 {
         bits_to_f64(self.bits)
     }
 
-    pub fn try_as_ptr(self) -> Option<Pointer> {
+    pub fn to_ptr(self) -> Pointer {
         self.relocation.map(|alloc_id| {
             Pointer::new(alloc_id, self.bits as usize)
-        })
+        }).unwrap_or_else(|| Pointer::from_int(self.bits as usize))
+    }
+
+    pub fn try_as_uint<'tcx>(self) -> EvalResult<'tcx, u64> {
+        self.to_ptr().to_int().map(|val| val as u64)
     }
 
     pub fn expect_uint(self, error_msg: &str) -> u64 {
-        if let Some(ptr) = self.try_as_ptr() {
-            return ptr.to_int().expect("non abstract ptr") as u64
+        if let Ok(int) = self.try_as_uint() {
+            return int;
         }
 
         use self::PrimValKind::*;
@@ -156,8 +160,8 @@ pub fn expect_uint(self, error_msg: &str) -> u64 {
     }
 
     pub fn expect_int(self, error_msg: &str) -> i64 {
-        if let Some(ptr) = self.try_as_ptr() {
-            return ptr.to_int().expect("non abstract ptr") as i64
+        if let Ok(int) = self.try_as_uint() {
+            return int as i64;
         }
 
         use self::PrimValKind::*;
@@ -188,15 +192,6 @@ pub fn expect_f64(self, error_msg: &str) -> f64 {
             _ => bug!("{}", error_msg),
         }
     }
-
-    pub fn expect_ptr(self, error_msg: &str) -> Pointer {
-        self.try_as_ptr().expect(error_msg)
-    }
-
-    /// FIXME(solson): Refactored into a duplicate of `expect_ptr`. Investigate removal.
-    pub fn expect_fn_ptr(self, error_msg: &str) -> Pointer {
-        self.try_as_ptr().expect(error_msg)
-    }
 }
 
 ////////////////////////////////////////////////////////////////////////////////
@@ -277,19 +272,13 @@ pub fn binary_op<'tcx>(
     use rustc::mir::BinOp::*;
     use self::PrimValKind::*;
 
-    match (left.try_as_ptr(), right.try_as_ptr()) {
-        (Some(left_ptr), Some(right_ptr)) => {
-            if left_ptr.alloc_id != right_ptr.alloc_id {
-                return Ok((unrelated_ptr_ops(bin_op)?, false));
-            }
-
-            // If the pointers are into the same allocation, fall through to the more general match
-            // later, which will do comparisons on the `bits` fields, which are the pointer offsets
-            // in this case.
-        }
-
-        (None, None) => {}
-        _ => return Err(EvalError::ReadPointerAsBytes),
+    // If the pointers are into the same allocation, fall through to the more general match
+    // later, which will do comparisons on the `bits` fields, which are the pointer offsets
+    // in this case.
+    let left_ptr = left.to_ptr();
+    let right_ptr = right.to_ptr();
+    if left_ptr.alloc_id != right_ptr.alloc_id {
+        return Ok((unrelated_ptr_ops(bin_op, left_ptr, right_ptr)?, false));
     }
 
     let (l, r) = (left.bits, right.bits);
@@ -376,12 +365,15 @@ pub fn binary_op<'tcx>(
     Ok((val, false))
 }
 
-fn unrelated_ptr_ops<'tcx>(bin_op: mir::BinOp) -> EvalResult<'tcx, PrimVal> {
+fn unrelated_ptr_ops<'tcx>(bin_op: mir::BinOp, left: Pointer, right: Pointer) -> EvalResult<'tcx, PrimVal> {
     use rustc::mir::BinOp::*;
     match bin_op {
         Eq => Ok(PrimVal::from_bool(false)),
         Ne => Ok(PrimVal::from_bool(true)),
         Lt | Le | Gt | Ge => Err(EvalError::InvalidPointerMath),
+        _ if left.to_int().is_ok() ^ right.to_int().is_ok() => {
+            Err(EvalError::ReadPointerAsBytes)
+        },
         _ => bug!(),
     }
 }
diff --git a/tests/compile-fail/cast_int_to_fn_ptr.rs b/tests/compile-fail/cast_int_to_fn_ptr.rs
new file mode 100644 (file)
index 0000000..dc39f7d
--- /dev/null
@@ -0,0 +1,7 @@
+fn main() {
+    let g = unsafe {
+        std::mem::transmute::<usize, fn(i32)>(42)
+    };
+
+    g(42) //~ ERROR tried to use an integer pointer or a dangling pointer as a function pointer
+}