Skip to content

Commit 1b676a5

Browse files
committed
rustc: check for signed division/remainder overflow.
1 parent 6e236aa commit 1b676a5

File tree

1 file changed

+35
-7
lines changed

1 file changed

+35
-7
lines changed

src/librustc/middle/const_eval.rs

Lines changed: 35 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ use syntax::{ast_map, ast_util, codemap};
2626

2727
use std::cmp::Ordering;
2828
use std::collections::hash_map::Entry::Vacant;
29+
use std::{i8, i16, i32, i64};
2930
use std::rc::Rc;
3031

3132
fn lookup_const<'a>(tcx: &'a ty::ctxt, e: &Expr) -> Option<&'a Expr> {
@@ -262,19 +263,46 @@ pub fn eval_const_expr_partial<'tcx>(tcx: &ty::ctxt<'tcx>,
262263
}
263264
}
264265
(Ok(const_int(a)), Ok(const_int(b))) => {
266+
let is_a_min_value = |&:| {
267+
let int_ty = match ty::expr_ty_opt(tcx, e).map(|ty| &ty.sty) {
268+
Some(&ty::ty_int(int_ty)) => int_ty,
269+
_ => return false
270+
};
271+
let int_ty = if let ast::TyIs(_) = int_ty {
272+
tcx.sess.target.int_type
273+
} else {
274+
int_ty
275+
};
276+
match int_ty {
277+
ast::TyI8 => (a as i8) == i8::MIN,
278+
ast::TyI16 => (a as i16) == i16::MIN,
279+
ast::TyI32 => (a as i32) == i32::MIN,
280+
ast::TyI64 => (a as i64) == i64::MIN,
281+
ast::TyIs(_) => unreachable!()
282+
}
283+
};
265284
match op.node {
266285
ast::BiAdd => Ok(const_int(a + b)),
267286
ast::BiSub => Ok(const_int(a - b)),
268287
ast::BiMul => Ok(const_int(a * b)),
269-
ast::BiDiv if b == 0 => {
270-
Err("attempted to divide by zero".to_string())
288+
ast::BiDiv => {
289+
if b == 0 {
290+
Err("attempted to divide by zero".to_string())
291+
} else if b == -1 && is_a_min_value() {
292+
Err("attempted to divide with overflow".to_string())
293+
} else {
294+
Ok(const_int(a / b))
295+
}
271296
}
272-
ast::BiDiv => Ok(const_int(a / b)),
273-
ast::BiRem if b == 0 => {
274-
Err("attempted remainder with a divisor of \
275-
zero".to_string())
297+
ast::BiRem => {
298+
if b == 0 {
299+
Err("attempted remainder with a divisor of zero".to_string())
300+
} else if b == -1 && is_a_min_value() {
301+
Err("attempted remainder with overflow".to_string())
302+
} else {
303+
Ok(const_int(a % b))
304+
}
276305
}
277-
ast::BiRem => Ok(const_int(a % b)),
278306
ast::BiAnd | ast::BiBitAnd => Ok(const_int(a & b)),
279307
ast::BiOr | ast::BiBitOr => Ok(const_int(a | b)),
280308
ast::BiBitXor => Ok(const_int(a ^ b)),

0 commit comments

Comments
 (0)