]> git.lizzy.rs Git - rust.git/blobdiff - src/shims/mod.rs
avoid using unchecked casts or arithmetic
[rust.git] / src / shims / mod.rs
index 2889807bf76aa1837d53eeed9c36bfc25b72a617..d9e4d226ecc9a6d428751be0f3b08baf3c3f71e1 100644 (file)
@@ -7,9 +7,12 @@
 pub mod time;
 pub mod tls;
 
-use crate::*;
+use std::convert::TryFrom;
+
 use rustc::{mir, ty};
 
+use crate::*;
+
 impl<'mir, 'tcx> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {}
 pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx> {
     fn find_mir_or_eval_fn(
@@ -24,12 +27,7 @@ fn find_mir_or_eval_fn(
 
         // There are some more lang items we want to hook that CTFE does not hook (yet).
         if this.tcx.lang_items().align_offset_fn() == Some(instance.def.def_id()) {
-            let (dest, ret) = ret.unwrap();
-            let n = this
-                .align_offset(args[0], args[1])?
-                .unwrap_or_else(|| this.truncate(u128::max_value(), dest.layout));
-            this.write_scalar(Scalar::from_uint(n, dest.layout.size), dest)?;
-            this.go_to_block(ret);
+            this.align_offset(args[0], args[1], ret, unwind)?;
             return Ok(None);
         }
 
@@ -52,35 +50,42 @@ fn align_offset(
         &mut self,
         ptr_op: OpTy<'tcx, Tag>,
         align_op: OpTy<'tcx, Tag>,
-    ) -> InterpResult<'tcx, Option<u128>> {
+        ret: Option<(PlaceTy<'tcx, Tag>, mir::BasicBlock)>,
+        unwind: Option<mir::BasicBlock>,
+    ) -> InterpResult<'tcx> {
         let this = self.eval_context_mut();
+        let (dest, ret) = ret.unwrap();
 
         let req_align = this
-            .force_bits(this.read_scalar(align_op)?.not_undef()?, this.pointer_size())?
-            as usize;
+            .force_bits(this.read_scalar(align_op)?.not_undef()?, this.pointer_size())?;
 
-        // FIXME: This should actually panic in the interpreted program
+        // Stop if the alignment is not a power of two.
         if !req_align.is_power_of_two() {
-            throw_unsup_format!("Required alignment should always be a power of two")
+            return this.start_panic("align_offset: align is not a power-of-two", unwind);
         }
 
         let ptr_scalar = this.read_scalar(ptr_op)?.not_undef()?;
 
+        // Default: no result.
+        let mut result = this.truncate(u128::MAX, dest.layout);
         if let Ok(ptr) = this.force_ptr(ptr_scalar) {
+            // Only do anything if we can identify the allocation this goes to.
             let cur_align =
-                this.memory.get_size_and_align(ptr.alloc_id, AllocCheck::MaybeDead)?.1.bytes()
-                    as usize;
-            if cur_align >= req_align {
-                // if the allocation alignment is at least the required alignment we use the
-                // libcore implementation
-                return Ok(Some(
+                this.memory.get_size_and_align(ptr.alloc_id, AllocCheck::MaybeDead)?.1.bytes();
+            if u128::from(cur_align) >= req_align {
+                // If the allocation alignment is at least the required alignment we use the
+                // libcore implementation.
+                // FIXME: is this correct in case of truncation?
+                result = u128::try_from(
                     (this.force_bits(ptr_scalar, this.pointer_size())? as *const i8)
-                        .align_offset(req_align) as u128,
-                ));
+                        .align_offset(usize::try_from(req_align).unwrap())
+                ).unwrap();
             }
         }
-        // If the allocation alignment is smaller than then required alignment or the pointer was
-        // actually an integer, we return `None`
-        Ok(None)
+
+        // Return result, and jump to caller.
+        this.write_scalar(Scalar::from_uint(result, dest.layout.size), dest)?;
+        this.go_to_block(ret);
+        Ok(())
     }
 }