about summary refs log tree commit diff
path: root/compiler
diff options
context:
space:
mode:
authorMatthias Krüger <matthias.krueger@famsik.de>2022-04-01 06:59:44 +0200
committerGitHub <noreply@github.com>2022-04-01 06:59:44 +0200
commitcdf178f776371bb0320769f95810c3c4fa668404 (patch)
tree36a08f5a44ac652bec46989148e3d43528b79d1c /compiler
parent40be7d3d487ca89460f5298baa4e678a016d39cf (diff)
parentcb0d15b0904aacc8f6106a68e17d234d466a027e (diff)
downloadrust-cdf178f776371bb0320769f95810c3c4fa668404.tar.gz
rust-cdf178f776371bb0320769f95810c3c4fa668404.zip
Rollup merge of #95388 - RalfJung:rust-val-limit, r=oli-obk
interpret: make isize::MAX the limit for dynamic value sizes

We are currently enforcing `data_layout.obj_size_bound()` as the maximal dynamic size of a Rust value (including for `size_of_val_raw`), but that does not match the docs.

In particular, Miri currently falsely says that this code has UB:
```rust
#![feature(layout_for_ptr)]
fn main() {
    let size = isize::MAX as usize;
    // Creating a raw slice of size isize::MAX and asking for its size is okay.
    let s = std::ptr::slice_from_raw_parts(1usize as *const u8, size);
    assert_eq!(size, unsafe { std::mem::size_of_val_raw(s) });
}
```
Diffstat (limited to 'compiler')
-rw-r--r--compiler/rustc_const_eval/src/interpret/eval_context.rs14
-rw-r--r--compiler/rustc_const_eval/src/interpret/intrinsics.rs8
-rw-r--r--compiler/rustc_const_eval/src/interpret/traits.rs5
-rw-r--r--compiler/rustc_middle/src/mir/interpret/pointer.rs5
4 files changed, 23 insertions, 9 deletions
diff --git a/compiler/rustc_const_eval/src/interpret/eval_context.rs b/compiler/rustc_const_eval/src/interpret/eval_context.rs
index abd7094440e..1b8186b5aad 100644
--- a/compiler/rustc_const_eval/src/interpret/eval_context.rs
+++ b/compiler/rustc_const_eval/src/interpret/eval_context.rs
@@ -23,8 +23,8 @@ use rustc_target::abi::{call::FnAbi, Align, HasDataLayout, Size, TargetDataLayou
 
 use super::{
     AllocCheck, AllocId, GlobalId, Immediate, InterpErrorInfo, InterpResult, MPlaceTy, Machine,
-    MemPlace, MemPlaceMeta, Memory, MemoryKind, Operand, Place, PlaceTy, Pointer, Provenance,
-    Scalar, ScalarMaybeUninit, StackPopJump,
+    MemPlace, MemPlaceMeta, Memory, MemoryKind, Operand, Place, PlaceTy, Pointer,
+    PointerArithmetic, Provenance, Scalar, ScalarMaybeUninit, StackPopJump,
 };
 use crate::transform::validate::equal_up_to_regions;
 
@@ -678,7 +678,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
                 let size = size.align_to(align);
 
                 // Check if this brought us over the size limit.
-                if size.bytes() >= self.tcx.data_layout.obj_size_bound() {
+                if size > self.max_size_of_val() {
                     throw_ub!(InvalidMeta("total size is bigger than largest supported object"));
                 }
                 Ok(Some((size, align)))
@@ -694,9 +694,11 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
                 let elem = layout.field(self, 0);
 
                 // Make sure the slice is not too big.
-                let size = elem.size.checked_mul(len, self).ok_or_else(|| {
-                    err_ub!(InvalidMeta("slice is bigger than largest supported object"))
-                })?;
+                let size = elem.size.bytes().saturating_mul(len); // we rely on `max_size_of_val` being smaller than `u64::MAX`.
+                let size = Size::from_bytes(size);
+                if size > self.max_size_of_val() {
+                    throw_ub!(InvalidMeta("slice is bigger than largest supported object"));
+                }
                 Ok(Some((size, elem.align.abi)))
             }
 
diff --git a/compiler/rustc_const_eval/src/interpret/intrinsics.rs b/compiler/rustc_const_eval/src/interpret/intrinsics.rs
index 5eff7d693c5..c80d7d71787 100644
--- a/compiler/rustc_const_eval/src/interpret/intrinsics.rs
+++ b/compiler/rustc_const_eval/src/interpret/intrinsics.rs
@@ -531,7 +531,9 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
     ) -> InterpResult<'tcx, Pointer<Option<M::PointerTag>>> {
         // We cannot overflow i64 as a type's size must be <= isize::MAX.
         let pointee_size = i64::try_from(self.layout_of(pointee_ty)?.size.bytes()).unwrap();
-        // The computed offset, in bytes, cannot overflow an isize.
+        // The computed offset, in bytes, must not overflow an isize.
+        // `checked_mul` enforces a too small bound, but no actual allocation can be big enough for
+        // the difference to be noticeable.
         let offset_bytes =
             offset_count.checked_mul(pointee_size).ok_or(err_ub!(PointerArithOverflow))?;
         // The offset being in bounds cannot rely on "wrapping around" the address space.
@@ -563,6 +565,8 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
         let count = self.read_scalar(&count)?.to_machine_usize(self)?;
         let layout = self.layout_of(src.layout.ty.builtin_deref(true).unwrap().ty)?;
         let (size, align) = (layout.size, layout.align.abi);
+        // `checked_mul` enforces a too small bound (the correct one would probably be machine_isize_max),
+        // but no actual allocation can be big enough for the difference to be noticeable.
         let size = size.checked_mul(count, self).ok_or_else(|| {
             err_ub_format!(
                 "overflow computing total size of `{}`",
@@ -588,6 +592,8 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
         let byte = self.read_scalar(&byte)?.to_u8()?;
         let count = self.read_scalar(&count)?.to_machine_usize(self)?;
 
+        // `checked_mul` enforces a too small bound (the correct one would probably be machine_isize_max),
+        // but no actual allocation can be big enough for the difference to be noticeable.
         let len = layout
             .size
             .checked_mul(count, self)
diff --git a/compiler/rustc_const_eval/src/interpret/traits.rs b/compiler/rustc_const_eval/src/interpret/traits.rs
index 131674decc9..fc60a40e2ad 100644
--- a/compiler/rustc_const_eval/src/interpret/traits.rs
+++ b/compiler/rustc_const_eval/src/interpret/traits.rs
@@ -110,16 +110,17 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
             .read_ptr_sized(pointer_size * u64::try_from(COMMON_VTABLE_ENTRIES_SIZE).unwrap())?
             .check_init()?;
         let size = size.to_machine_usize(self)?;
+        let size = Size::from_bytes(size);
         let align = vtable
             .read_ptr_sized(pointer_size * u64::try_from(COMMON_VTABLE_ENTRIES_ALIGN).unwrap())?
             .check_init()?;
         let align = align.to_machine_usize(self)?;
         let align = Align::from_bytes(align).map_err(|e| err_ub!(InvalidVtableAlignment(e)))?;
 
-        if size >= self.tcx.data_layout.obj_size_bound() {
+        if size > self.max_size_of_val() {
             throw_ub!(InvalidVtableSize);
         }
-        Ok((Size::from_bytes(size), align))
+        Ok((size, align))
     }
 
     pub fn read_new_vtable_after_trait_upcasting_from_vtable(
diff --git a/compiler/rustc_middle/src/mir/interpret/pointer.rs b/compiler/rustc_middle/src/mir/interpret/pointer.rs
index 7d101046a96..813c0912f53 100644
--- a/compiler/rustc_middle/src/mir/interpret/pointer.rs
+++ b/compiler/rustc_middle/src/mir/interpret/pointer.rs
@@ -18,6 +18,11 @@ pub trait PointerArithmetic: HasDataLayout {
         self.data_layout().pointer_size
     }
 
+    #[inline(always)]
+    fn max_size_of_val(&self) -> Size {
+        Size::from_bytes(self.machine_isize_max())
+    }
+
     #[inline]
     fn machine_usize_max(&self) -> u64 {
         self.pointer_size().unsigned_int_max().try_into().unwrap()