]> git.proxmox.com Git - rustc.git/blobdiff - compiler/rustc_const_eval/src/interpret/intrinsics.rs
New upstream version 1.62.1+dfsg1
[rustc.git] / compiler / rustc_const_eval / src / interpret / intrinsics.rs
index c80d7d71787422ced418d9ea410c8c012ecd81cb..59ea40dc2f94e3bd85654ae5c776ae39c1becb97 100644 (file)
@@ -188,7 +188,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
                 let val = self.read_scalar(&args[0])?.check_init()?;
                 let bits = val.to_bits(layout_of.size)?;
                 let kind = match layout_of.abi {
-                    Abi::Scalar(scalar) => scalar.value,
+                    Abi::Scalar(scalar) => scalar.primitive(),
                     _ => span_bug!(
                         self.cur_span(),
                         "{} called on invalid type {:?}",
@@ -308,7 +308,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
                 let offset_ptr = ptr.wrapping_signed_offset(offset_bytes, self);
                 self.write_pointer(offset_ptr, dest)?;
             }
-            sym::ptr_offset_from => {
+            sym::ptr_offset_from | sym::ptr_offset_from_unsigned => {
                 let a = self.read_pointer(&args[0])?;
                 let b = self.read_pointer(&args[1])?;
 
@@ -318,7 +318,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
                 // exception from the exception.)
                 // This is the dual to the special exception for offset-by-0
                 // in the inbounds pointer offset operation (see `ptr_offset_inbounds` below).
-                match (self.memory.ptr_try_get_alloc(a), self.memory.ptr_try_get_alloc(b)) {
+                match (self.ptr_try_get_alloc_id(a), self.ptr_try_get_alloc_id(b)) {
                     (Err(a), Err(b)) if a == b && a != 0 => {
                         // Both are the same non-null integer.
                         self.write_scalar(Scalar::from_machine_isize(0, self), dest)?;
@@ -330,34 +330,57 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
                         // Both are pointers. They must be into the same allocation.
                         if a_alloc_id != b_alloc_id {
                             throw_ub_format!(
-                                "ptr_offset_from cannot compute offset of pointers into different \
-                                allocations.",
+                                "{} cannot compute offset of pointers into different allocations.",
+                                intrinsic_name,
                             );
                         }
                         // And they must both be valid for zero-sized accesses ("in-bounds or one past the end").
-                        self.memory.check_ptr_access_align(
+                        self.check_ptr_access_align(
                             a,
                             Size::ZERO,
                             Align::ONE,
                             CheckInAllocMsg::OffsetFromTest,
                         )?;
-                        self.memory.check_ptr_access_align(
+                        self.check_ptr_access_align(
                             b,
                             Size::ZERO,
                             Align::ONE,
                             CheckInAllocMsg::OffsetFromTest,
                         )?;
 
+                        if intrinsic_name == sym::ptr_offset_from_unsigned && a_offset < b_offset {
+                            throw_ub_format!(
+                                "{} cannot compute a negative offset, but {} < {}",
+                                intrinsic_name,
+                                a_offset.bytes(),
+                                b_offset.bytes(),
+                            );
+                        }
+
                         // Compute offset.
                         let usize_layout = self.layout_of(self.tcx.types.usize)?;
                         let isize_layout = self.layout_of(self.tcx.types.isize)?;
-                        let a_offset = ImmTy::from_uint(a_offset.bytes(), usize_layout);
-                        let b_offset = ImmTy::from_uint(b_offset.bytes(), usize_layout);
-                        let (val, _overflowed, _ty) =
+                        let ret_layout = if intrinsic_name == sym::ptr_offset_from {
+                            isize_layout
+                        } else {
+                            usize_layout
+                        };
+
+                        // The subtraction is always done in `isize` to enforce
+                        // the "no more than `isize::MAX` apart" requirement.
+                        let a_offset = ImmTy::from_uint(a_offset.bytes(), isize_layout);
+                        let b_offset = ImmTy::from_uint(b_offset.bytes(), isize_layout);
+                        let (val, overflowed, _ty) =
                             self.overflowing_binary_op(BinOp::Sub, &a_offset, &b_offset)?;
+                        if overflowed {
+                            throw_ub_format!("Pointers were too far apart for {}", intrinsic_name);
+                        }
+
                         let pointee_layout = self.layout_of(substs.type_at(0))?;
-                        let val = ImmTy::from_scalar(val, isize_layout);
-                        let size = ImmTy::from_int(pointee_layout.size.bytes(), isize_layout);
+                        // This re-interprets an isize at ret_layout, but we already checked
+                        // that if ret_layout is usize, then the result must be non-negative.
+                        let val = ImmTy::from_scalar(val, ret_layout);
+                        let size = ImmTy::from_int(pointee_layout.size.bytes(), ret_layout);
                         self.exact_div(&val, &size, dest)?;
                     }
                 }
@@ -545,7 +568,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
         let min_ptr = if offset_bytes >= 0 { ptr } else { offset_ptr };
         let size = offset_bytes.unsigned_abs();
         // This call handles checking for integer/null pointers.
-        self.memory.check_ptr_access_align(
+        self.check_ptr_access_align(
             min_ptr,
             Size::from_bytes(size),
             Align::ONE,
@@ -577,7 +600,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
         let src = self.read_pointer(&src)?;
         let dst = self.read_pointer(&dst)?;
 
-        self.memory.copy(src, align, dst, align, size, nonoverlapping)
+        self.mem_copy(src, align, dst, align, size, nonoverlapping)
     }
 
     pub(crate) fn write_bytes_intrinsic(
@@ -600,7 +623,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
             .ok_or_else(|| err_ub_format!("overflow computing total size of `write_bytes`"))?;
 
         let bytes = std::iter::repeat(byte).take(len.bytes_usize());
-        self.memory.write_bytes(dst, bytes)
+        self.write_bytes_ptr(dst, bytes)
     }
 
     pub(crate) fn raw_eq_intrinsic(
@@ -613,8 +636,8 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
 
         let lhs = self.read_pointer(lhs)?;
         let rhs = self.read_pointer(rhs)?;
-        let lhs_bytes = self.memory.read_bytes(lhs, layout.size)?;
-        let rhs_bytes = self.memory.read_bytes(rhs, layout.size)?;
+        let lhs_bytes = self.read_bytes_ptr(lhs, layout.size)?;
+        let rhs_bytes = self.read_bytes_ptr(rhs, layout.size)?;
         Ok(Scalar::from_bool(lhs_bytes == rhs_bytes))
     }
 }