about summary refs log tree commit diff
diff options
context:
space:
mode:
authorRalf Jung <post@ralfj.de>2024-08-01 14:38:58 +0200
committerRalf Jung <post@ralfj.de>2024-08-01 14:38:58 +0200
commitdb1652e07b7e6f81692795e7cb3b8c02798b1756 (patch)
tree435196003ac45963e802611698552941ac293754
parent5d5c97aad7cd2803b6dbecdd34293616065dc6b2 (diff)
downloadrust-db1652e07b7e6f81692795e7cb3b8c02798b1756.tar.gz
rust-db1652e07b7e6f81692795e7cb3b8c02798b1756.zip
fix the way we detect overflow for inbounds arithmetic (and tweak the error message)
-rw-r--r--compiler/rustc_const_eval/messages.ftl2
-rw-r--r--compiler/rustc_const_eval/src/interpret/operator.rs22
-rw-r--r--tests/ui/consts/offset_ub.stderr4
3 files changed, 17 insertions, 11 deletions
diff --git a/compiler/rustc_const_eval/messages.ftl b/compiler/rustc_const_eval/messages.ftl
index e02d6ebb183..94cdd021d8d 100644
--- a/compiler/rustc_const_eval/messages.ftl
+++ b/compiler/rustc_const_eval/messages.ftl
@@ -277,7 +277,7 @@ const_eval_partial_pointer_copy =
 const_eval_partial_pointer_overwrite =
     unable to overwrite parts of a pointer in memory at {$ptr}
 const_eval_pointer_arithmetic_overflow =
-    overflowing in-bounds pointer arithmetic
+    overflowing pointer arithmetic: the total offset in bytes does not fit in an `isize`
 const_eval_pointer_arithmetic_test = out-of-bounds pointer arithmetic
 const_eval_pointer_out_of_bounds =
     {$bad_pointer_message}: {const_eval_expected_inbounds_pointer}, but got {$pointer} {$ptr_offset_is_neg ->
diff --git a/compiler/rustc_const_eval/src/interpret/operator.rs b/compiler/rustc_const_eval/src/interpret/operator.rs
index 3263c90ec72..fe5869ad7fa 100644
--- a/compiler/rustc_const_eval/src/interpret/operator.rs
+++ b/compiler/rustc_const_eval/src/interpret/operator.rs
@@ -7,7 +7,7 @@ use rustc_middle::{bug, mir, span_bug};
 use rustc_span::symbol::sym;
 use tracing::trace;
 
-use super::{err_ub, throw_ub, ImmTy, InterpCx, Machine, MemPlaceMeta};
+use super::{throw_ub, ImmTy, InterpCx, Machine, MemPlaceMeta};
 
 impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
     fn three_way_compare<T: Ord>(&self, lhs: T, rhs: T) -> ImmTy<'tcx, M::Provenance> {
@@ -298,17 +298,23 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
             // Pointer ops that are always supported.
             Offset => {
                 let ptr = left.to_scalar().to_pointer(self)?;
-                let offset_count = right.to_scalar().to_target_isize(self)?;
                 let pointee_ty = left.layout.ty.builtin_deref(true).unwrap();
+                let pointee_layout = self.layout_of(pointee_ty)?;
+                assert!(pointee_layout.abi.is_sized());
 
                 // 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, 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))?;
+                let pointee_size = i64::try_from(pointee_layout.size.bytes()).unwrap();
+                let pointee_size = ImmTy::from_int(pointee_size, right.layout);
+                // Multiply element size and element count.
+                let (val, overflowed) = self
+                    .binary_op(mir::BinOp::MulWithOverflow, right, &pointee_size)?
+                    .to_scalar_pair();
+                // This must not overflow.
+                if overflowed.to_bool()? {
+                    throw_ub!(PointerArithOverflow)
+                }
 
+                let offset_bytes = val.to_target_isize(self)?;
                 let offset_ptr = self.ptr_offset_inbounds(ptr, offset_bytes)?;
                 Ok(ImmTy::from_scalar(Scalar::from_maybe_pointer(offset_ptr, self), left.layout))
             }
diff --git a/tests/ui/consts/offset_ub.stderr b/tests/ui/consts/offset_ub.stderr
index 29327569323..779cb9654f4 100644
--- a/tests/ui/consts/offset_ub.stderr
+++ b/tests/ui/consts/offset_ub.stderr
@@ -40,7 +40,7 @@ LL | pub const AFTER_ARRAY: *const u8 = unsafe { [0u8; 100].as_ptr().offset(101)
 error[E0080]: evaluation of constant value failed
   --> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
    |
-   = note: overflowing in-bounds pointer arithmetic
+   = note: overflowing pointer arithmetic: the total offset in bytes does not fit in an `isize`
    |
 note: inside `std::ptr::const_ptr::<impl *const u16>::offset`
   --> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
@@ -53,7 +53,7 @@ LL | pub const OVERFLOW: *const u16 = unsafe { [0u16; 1].as_ptr().offset(isize::
 error[E0080]: evaluation of constant value failed
   --> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
    |
-   = note: overflowing in-bounds pointer arithmetic
+   = note: overflowing pointer arithmetic: the total offset in bytes does not fit in an `isize`
    |
 note: inside `std::ptr::const_ptr::<impl *const u16>::offset`
   --> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL