diff options
Diffstat (limited to 'compiler/rustc_const_eval/src')
| -rw-r--r-- | compiler/rustc_const_eval/src/interpret/intrinsics.rs | 7 | ||||
| -rw-r--r-- | compiler/rustc_const_eval/src/interpret/operator.rs | 17 | ||||
| -rw-r--r-- | compiler/rustc_const_eval/src/interpret/projection.rs | 8 |
3 files changed, 25 insertions, 7 deletions
diff --git a/compiler/rustc_const_eval/src/interpret/intrinsics.rs b/compiler/rustc_const_eval/src/interpret/intrinsics.rs index 8a07f90c951..48ea8724aea 100644 --- a/compiler/rustc_const_eval/src/interpret/intrinsics.rs +++ b/compiler/rustc_const_eval/src/interpret/intrinsics.rs @@ -599,9 +599,8 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { let count = self.read_target_usize(count)?; let layout = self.layout_of(src.layout.ty.builtin_deref(true).unwrap())?; let (size, align) = (layout.size, layout.align.abi); - // `checked_mul` enforces a too small bound (the correct one would probably be target_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(|| { + + let size = self.compute_size_in_bytes(size, count).ok_or_else(|| { err_ub_custom!( fluent::const_eval_size_overflow, name = if nonoverlapping { "copy_nonoverlapping" } else { "copy" } @@ -649,7 +648,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { // `checked_mul` enforces a too small bound (the correct one would probably be target_isize_max), // but no actual allocation can be big enough for the difference to be noticeable. - let len = layout.size.checked_mul(count, self).ok_or_else(|| { + let len = self.compute_size_in_bytes(layout.size, count).ok_or_else(|| { err_ub_custom!(fluent::const_eval_size_overflow, name = "write_bytes") })?; diff --git a/compiler/rustc_const_eval/src/interpret/operator.rs b/compiler/rustc_const_eval/src/interpret/operator.rs index b390bb87789..5535d15aa8d 100644 --- a/compiler/rustc_const_eval/src/interpret/operator.rs +++ b/compiler/rustc_const_eval/src/interpret/operator.rs @@ -1,11 +1,12 @@ use either::Either; use rustc_apfloat::{Float, FloatConvert}; -use rustc_middle::mir::interpret::{InterpResult, Scalar}; +use rustc_middle::mir::interpret::{InterpResult, PointerArithmetic, Scalar}; use rustc_middle::mir::NullOp; use rustc_middle::ty::layout::{LayoutOf, TyAndLayout}; use rustc_middle::ty::{self, FloatTy, ScalarInt, Ty}; use rustc_middle::{bug, mir, span_bug}; use rustc_span::symbol::sym; +use rustc_target::abi::Size; use tracing::trace; use super::{throw_ub, ImmTy, InterpCx, Machine, MemPlaceMeta}; @@ -287,6 +288,20 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { }) } + /// Computes the total size of this access, `count * elem_size`, + /// checking for overflow beyond isize::MAX. + pub(super) fn compute_size_in_bytes(&self, elem_size: Size, count: u64) -> Option<Size> { + // `checked_mul` applies `u64` limits independent of the target pointer size... but the + // subsequent check for `max_size_of_val` means we also handle 32bit targets correctly. + // (We cannot use `Size::checked_mul` as that enforces `obj_size_bound` as the limit, which + // would be wrong here.) + elem_size + .bytes() + .checked_mul(count) + .map(Size::from_bytes) + .filter(|&total| total <= self.max_size_of_val()) + } + fn binary_ptr_op( &self, bin_op: mir::BinOp, diff --git a/compiler/rustc_const_eval/src/interpret/projection.rs b/compiler/rustc_const_eval/src/interpret/projection.rs index 641ed5bb7c0..4e8b66907be 100644 --- a/compiler/rustc_const_eval/src/interpret/projection.rs +++ b/compiler/rustc_const_eval/src/interpret/projection.rs @@ -17,7 +17,7 @@ use rustc_target::abi::{self, Size, VariantIdx}; use tracing::{debug, instrument}; use super::{ - throw_ub, throw_unsup, InterpCx, InterpResult, MPlaceTy, Machine, MemPlaceMeta, OpTy, + err_ub, throw_ub, throw_unsup, InterpCx, InterpResult, MPlaceTy, Machine, MemPlaceMeta, OpTy, Provenance, Scalar, }; @@ -229,7 +229,11 @@ where // This can only be reached in ConstProp and non-rustc-MIR. throw_ub!(BoundsCheckFailed { len, index }); } - let offset = stride * index; // `Size` multiplication + // With raw slices, `len` can be so big that this *can* overflow. + let offset = self + .compute_size_in_bytes(stride, index) + .ok_or_else(|| err_ub!(PointerArithOverflow))?; + // All fields have the same layout. let field_layout = base.layout().field(self, 0); (offset, field_layout) |
