diff --git a/src/error.rs b/src/error.rs index dc7b227b7972..1a8ca2d03ca6 100644 --- a/src/error.rs +++ b/src/error.rs @@ -23,7 +23,6 @@ pub enum EvalError<'tcx> { }, ReadPointerAsBytes, InvalidPointerMath, - OverflowingPointerMath, ReadUndefBytes, DeadLocal, InvalidBoolOp(mir::BinOp), @@ -32,6 +31,7 @@ pub enum EvalError<'tcx> { ExecuteMemory, ArrayIndexOutOfBounds(Span, u64, u64), Math(Span, ConstMathErr), + OverflowingMath, InvalidChar(u128), OutOfMemory { allocation_size: u64, @@ -83,8 +83,6 @@ impl<'tcx> Error for EvalError<'tcx> { "a raw memory access tried to access part of a pointer value as raw bytes", EvalError::InvalidPointerMath => "attempted to do math or a comparison on pointers into different allocations", - EvalError::OverflowingPointerMath => - "attempted to do overflowing math on a pointer", EvalError::ReadUndefBytes => "attempted to read undefined bytes", EvalError::DeadLocal => @@ -100,6 +98,8 @@ impl<'tcx> Error for EvalError<'tcx> { "array index out of bounds", EvalError::Math(..) => "mathematical operation failed", + EvalError::OverflowingMath => + "attempted to do overflowing math", EvalError::NoMirFor(..) => "mir not found", EvalError::InvalidChar(..) => diff --git a/src/eval_context.rs b/src/eval_context.rs index d45c419c78a9..b9310f1f899a 100644 --- a/src/eval_context.rs +++ b/src/eval_context.rs @@ -452,8 +452,14 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> { } BinaryOp(bin_op, ref left, ref right) => { - // ignore overflow bit, rustc inserts check branches for us - self.intrinsic_overflowing(bin_op, left, right, dest, dest_ty)?; + if self.intrinsic_overflowing(bin_op, left, right, dest, dest_ty)? { + // There was an overflow in an unchecked binop. Right now, we consider this an error and bail out. + // The rationale is that the reason rustc emits unchecked binops in release mode (vs. the checked binops + // it emits in debug mode) is performance, but it doesn't cust us any performance in miri. + // If, however, the compiler ever starts transforming unchecked intrinsics into unchecked binops, + // we have to go back to just ignoring the overflow here. + return Err(EvalError::OverflowingMath); + } } CheckedBinaryOp(bin_op, ref left, ref right) => { @@ -869,7 +875,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> { self.memory.check_bounds(ptr, false)?; Ok(ptr) } else { - Err(EvalError::OverflowingPointerMath) + Err(EvalError::OverflowingMath) } } diff --git a/src/memory.rs b/src/memory.rs index 66180d6075c7..d663835bc1fc 100644 --- a/src/memory.rs +++ b/src/memory.rs @@ -73,7 +73,7 @@ impl Pointer { if let Some(res) = self.offset.checked_sub(n) { Ok(Pointer::new(self.alloc_id, res)) } else { - Err(EvalError::OverflowingPointerMath) + Err(EvalError::OverflowingMath) } } else { self.offset(i as u64, layout) @@ -83,12 +83,12 @@ impl Pointer { pub fn offset<'tcx>(self, i: u64, layout: &TargetDataLayout) -> EvalResult<'tcx, Self> { if let Some(res) = self.offset.checked_add(i) { if res as u128 >= (1u128 << layout.pointer_size.bits()) { - Err(EvalError::OverflowingPointerMath) + Err(EvalError::OverflowingMath) } else { Ok(Pointer::new(self.alloc_id, res)) } } else { - Err(EvalError::OverflowingPointerMath) + Err(EvalError::OverflowingMath) } } diff --git a/tests/compile-fail/out_of_bounds_ptr_2.rs b/tests/compile-fail/out_of_bounds_ptr_2.rs index 0bb670fd022f..f7546494574b 100644 --- a/tests/compile-fail/out_of_bounds_ptr_2.rs +++ b/tests/compile-fail/out_of_bounds_ptr_2.rs @@ -1,4 +1,4 @@ -// error-pattern: overflowing math on a pointer +// error-pattern: overflowing math fn main() { let v = [0i8; 4]; let x = &v as *const i8; diff --git a/tests/compile-fail/ptr_offset_overflow.rs b/tests/compile-fail/ptr_offset_overflow.rs index ebd972a87175..578468c3399b 100644 --- a/tests/compile-fail/ptr_offset_overflow.rs +++ b/tests/compile-fail/ptr_offset_overflow.rs @@ -1,4 +1,4 @@ -//error-pattern: overflowing math on a pointer +//error-pattern: overflowing math fn main() { let v = [1i8, 2]; let x = &v[1] as *const i8;