Skip to content

Commit 2daf62f

Browse files
authored
Merge pull request rust-lang#188 from RalfJung/overflow
Bail out on overflow
2 parents cad0188 + 3a5abf0 commit 2daf62f

File tree

7 files changed

+21
-14
lines changed

7 files changed

+21
-14
lines changed

src/error.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,6 @@ pub enum EvalError<'tcx> {
2323
},
2424
ReadPointerAsBytes,
2525
InvalidPointerMath,
26-
OverflowingPointerMath,
2726
ReadUndefBytes,
2827
DeadLocal,
2928
InvalidBoolOp(mir::BinOp),
@@ -32,6 +31,7 @@ pub enum EvalError<'tcx> {
3231
ExecuteMemory,
3332
ArrayIndexOutOfBounds(Span, u64, u64),
3433
Math(Span, ConstMathErr),
34+
OverflowingMath,
3535
InvalidChar(u128),
3636
OutOfMemory {
3737
allocation_size: u64,
@@ -83,8 +83,6 @@ impl<'tcx> Error for EvalError<'tcx> {
8383
"a raw memory access tried to access part of a pointer value as raw bytes",
8484
EvalError::InvalidPointerMath =>
8585
"attempted to do math or a comparison on pointers into different allocations",
86-
EvalError::OverflowingPointerMath =>
87-
"attempted to do overflowing math on a pointer",
8886
EvalError::ReadUndefBytes =>
8987
"attempted to read undefined bytes",
9088
EvalError::DeadLocal =>
@@ -100,6 +98,8 @@ impl<'tcx> Error for EvalError<'tcx> {
10098
"array index out of bounds",
10199
EvalError::Math(..) =>
102100
"mathematical operation failed",
101+
EvalError::OverflowingMath =>
102+
"attempted to do overflowing math",
103103
EvalError::NoMirFor(..) =>
104104
"mir not found",
105105
EvalError::InvalidChar(..) =>

src/eval_context.rs

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -452,8 +452,14 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
452452
}
453453

454454
BinaryOp(bin_op, ref left, ref right) => {
455-
// ignore overflow bit, rustc inserts check branches for us
456-
self.intrinsic_overflowing(bin_op, left, right, dest, dest_ty)?;
455+
if self.intrinsic_overflowing(bin_op, left, right, dest, dest_ty)? {
456+
// There was an overflow in an unchecked binop. Right now, we consider this an error and bail out.
457+
// The rationale is that the reason rustc emits unchecked binops in release mode (vs. the checked binops
458+
// it emits in debug mode) is performance, but it doesn't cost us any performance in miri.
459+
// If, however, the compiler ever starts transforming unchecked intrinsics into unchecked binops,
460+
// we have to go back to just ignoring the overflow here.
461+
return Err(EvalError::OverflowingMath);
462+
}
457463
}
458464

459465
CheckedBinaryOp(bin_op, ref left, ref right) => {
@@ -869,7 +875,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
869875
self.memory.check_bounds(ptr, false)?;
870876
Ok(ptr)
871877
} else {
872-
Err(EvalError::OverflowingPointerMath)
878+
Err(EvalError::OverflowingMath)
873879
}
874880
}
875881

src/memory.rs

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,7 @@ impl Pointer {
7373
if let Some(res) = self.offset.checked_sub(n) {
7474
Ok(Pointer::new(self.alloc_id, res))
7575
} else {
76-
Err(EvalError::OverflowingPointerMath)
76+
Err(EvalError::OverflowingMath)
7777
}
7878
} else {
7979
self.offset(i as u64, layout)
@@ -83,12 +83,12 @@ impl Pointer {
8383
pub fn offset<'tcx>(self, i: u64, layout: &TargetDataLayout) -> EvalResult<'tcx, Self> {
8484
if let Some(res) = self.offset.checked_add(i) {
8585
if res as u128 >= (1u128 << layout.pointer_size.bits()) {
86-
Err(EvalError::OverflowingPointerMath)
86+
Err(EvalError::OverflowingMath)
8787
} else {
8888
Ok(Pointer::new(self.alloc_id, res))
8989
}
9090
} else {
91-
Err(EvalError::OverflowingPointerMath)
91+
Err(EvalError::OverflowingMath)
9292
}
9393
}
9494

@@ -166,7 +166,8 @@ pub struct Memory<'a, 'tcx> {
166166
/// We mark memory as "packed" or "unaligned" for a single statement, and clear the marking
167167
/// afterwards. In the case where no packed structs are present, it's just a single emptyness
168168
/// check of a set instead of heavily influencing all memory access code as other solutions
169-
/// would.
169+
/// would. This is simpler than the alternative of passing a "packed" parameter to every
170+
/// load/store method.
170171
///
171172
/// One disadvantage of this solution is the fact that you can cast a pointer to a packed
172173
/// struct to a pointer to a normal struct and if you access a field of both in the same MIR

src/terminator/intrinsic.rs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,6 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
4343

4444

4545
"arith_offset" => {
46-
// FIXME: Switch to non-checked, wrapped version of pointer_offset
4746
let offset = self.value_to_primval(arg_vals[1], isize)?.to_i128()? as i64;
4847
let ptr = arg_vals[0].read_ptr(&self.memory)?;
4948
let result_ptr = self.wrapping_pointer_offset(ptr, substs.type_at(0), offset)?;

tests/compile-fail/out_of_bounds_ptr_2.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// error-pattern: overflowing math on a pointer
1+
// error-pattern: overflowing math
22
fn main() {
33
let v = [0i8; 4];
44
let x = &v as *const i8;

tests/compile-fail/ptr_offset_overflow.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
//error-pattern: overflowing math on a pointer
1+
//error-pattern: overflowing math
22
fn main() {
33
let v = [1i8, 2];
44
let x = &v[1] as *const i8;

tests/run-pass/aux_test.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
// aux-build:dep.rs
2-
// This ignores the test against rustc, but runs it against miri:
2+
33
// ignore-cross-compile
4+
// TODO: The above accidentally also ignores this test against rustc even when are are not cross-compiling.
45

56
extern crate dep;
67

0 commit comments

Comments
 (0)