Skip to content

Implement arithmetic overflow changes #22532

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 26 commits into from
Mar 3, 2015
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
dee5024
Avoid ICE when `FnCtxt::local_ty` cannot find type; issue error then,…
pnkfelix Feb 22, 2015
00ccc7a
Make `test/run-pass/backtrace.rs` more robust about own host environm…
pnkfelix Feb 19, 2015
cdfff9d
rustc: implement arithmetic overflow checking
emberian Jan 6, 2015
1246d40
Add `core::num::wrapping` and fix overflow errors.
Aatch Jan 9, 2015
280dea7
Implement parse_opt_bool better
Aatch Jan 9, 2015
6d6038a
Added `OverflowingOps` trait to core::num::wrapping.
pnkfelix Feb 19, 2015
eadc8a7
fix Iter::rposition for new arith-overflow checking.
pnkfelix Feb 18, 2015
cf18e9c
fix test generic-extern-mangle.rs
nikomatsakis Feb 18, 2015
e7c9861
Fixes to collections to accommodate arith-overflow changes.
pnkfelix Feb 19, 2015
4394720
Fix the overflowing tests in run-fail.
pnkfelix Feb 19, 2015
c8db89a
Accommodate arith-overflow in `core::num`, `std::num`, `coretest::num`.
pnkfelix Feb 19, 2015
7c8edab
Accommodate arith-overflow in serialize::json numeric parsing.
pnkfelix Feb 19, 2015
6189e99
Accommodate arith-overflow in `rand` and `std::rand`.
pnkfelix Feb 19, 2015
f0404c3
`core::iter`: fix bug uncovered by arith-overflow.
pnkfelix Feb 20, 2015
faf3bcd
Accommodate simple cases of arith-overflow in `rustc` related crates.
pnkfelix Feb 20, 2015
f1ea2b3
Catch arith-overflow explicitly during `rustc::middle::const_eval`.
pnkfelix Feb 20, 2015
f9bbef7
Avoid fatal errors in astconv; just err and return `ty_err` instead.
pnkfelix Feb 22, 2015
e919f82
Address arith-overflow and error-handling in `const_eval.rs`.
pnkfelix Feb 22, 2015
5d950bd
Switch to `eval_const_expr_partial` when `check_match.rs` checks for …
pnkfelix Feb 22, 2015
46de12a
Switch to eval_const_expr_partial in `trans::consts`.
pnkfelix Feb 22, 2015
8491c82
Update tests for const-eval error handling changes.
pnkfelix Feb 22, 2015
b85b3c9
Fix span typo in the arithmetic overflow for array length reporting.
pnkfelix Feb 27, 2015
11057fe
Incorporated first review sugestion from eddyb.
pnkfelix Feb 27, 2015
4e23179
Incorporated second review suggestion from eddyb.
pnkfelix Mar 1, 2015
185c074
Fix backtrace tests for Linux
Manishearth Mar 2, 2015
243c516
sidestep potential over- and underflow in estimated stack bounds.
pnkfelix Mar 3, 2015
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions src/libcollections/bit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -818,19 +818,19 @@ impl BitVec {
let full_value = if value { !0 } else { 0 };

// Correct the old tail word, setting or clearing formerly unused bits
let old_last_word = blocks_for_bits(self.nbits) - 1;
let num_cur_blocks = blocks_for_bits(self.nbits);
if self.nbits % u32::BITS as usize > 0 {
let mask = mask_for_bits(self.nbits);
if value {
self.storage[old_last_word] |= !mask;
self.storage[num_cur_blocks - 1] |= !mask;
} else {
// Extra bits are already zero by invariant.
}
}

// Fill in words after the old tail word
let stop_idx = cmp::min(self.storage.len(), new_nblocks);
for idx in old_last_word + 1..stop_idx {
for idx in num_cur_blocks..stop_idx {
self.storage[idx] = full_value;
}

Expand Down
4 changes: 2 additions & 2 deletions src/libcollections/btree/map.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ use core::fmt::Debug;
use core::hash::{Hash, Hasher};
use core::iter::{Map, FromIterator, IntoIterator};
use core::ops::{Index, IndexMut};
use core::{iter, fmt, mem};
use core::{iter, fmt, mem, usize};
use Bound::{self, Included, Excluded, Unbounded};

use borrow::Borrow;
Expand Down Expand Up @@ -1467,7 +1467,7 @@ macro_rules! range_impl {
$Range {
inner: AbsIter {
traversals: traversals,
size: 0, // unused
size: usize::MAX, // unused
}
}
}
Expand Down
3 changes: 2 additions & 1 deletion src/libcollections/btree/node.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1215,7 +1215,8 @@ impl<K, V> Node<K, V> {
ptr::copy(
self.edges_mut().as_mut_ptr().offset(index as isize),
self.edges().as_ptr().offset(index as isize + 1),
self.len() - index + 1
// index can be == len+1, so do the +1 first to avoid underflow.
(self.len() + 1) - index
);

edge
Expand Down
11 changes: 8 additions & 3 deletions src/libcollections/slice.rs
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,7 @@ use core::iter::{range_step, MultiplicativeIterator};
use core::marker::Sized;
use core::mem::size_of;
use core::mem;
use core::num::wrapping::WrappingOps;
use core::ops::FnMut;
use core::option::Option::{self, Some, None};
use core::ptr::PtrExt;
Expand Down Expand Up @@ -1209,18 +1210,22 @@ struct SizeDirection {
impl Iterator for ElementSwaps {
type Item = (usize, usize);

#[inline]
// #[inline]
fn next(&mut self) -> Option<(usize, usize)> {
fn new_pos_wrapping(i: usize, s: Direction) -> usize {
i.wrapping_add(match s { Pos => 1, Neg => -1 })
}

fn new_pos(i: usize, s: Direction) -> usize {
i + match s { Pos => 1, Neg => -1 }
match s { Pos => i + 1, Neg => i - 1 }
}

// Find the index of the largest mobile element:
// The direction should point into the vector, and the
// swap should be with a smaller `size` element.
let max = self.sdir.iter().cloned().enumerate()
.filter(|&(i, sd)|
new_pos(i, sd.dir) < self.sdir.len() &&
new_pos_wrapping(i, sd.dir) < self.sdir.len() &&
self.sdir[new_pos(i, sd.dir)].size < sd.size)
.max_by(|&(_, sd)| sd.size);
match max {
Expand Down
67 changes: 41 additions & 26 deletions src/libcollections/vec_deque.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ use core::fmt;
use core::iter::{self, repeat, FromIterator, IntoIterator, RandomAccessIterator};
use core::mem;
use core::num::{Int, UnsignedInt};
use core::num::wrapping::WrappingOps;
use core::ops::{Index, IndexMut};
use core::ptr::{self, Unique};
use core::raw::Slice as RawSlice;
Expand Down Expand Up @@ -120,6 +121,20 @@ impl<T> VecDeque<T> {
#[inline]
fn wrap_index(&self, idx: usize) -> usize { wrap_index(idx, self.cap) }

/// Returns the index in the underlying buffer for a given logical element
/// index + addend.
#[inline]
fn wrap_add(&self, idx: usize, addend: usize) -> usize {
wrap_index(idx.wrapping_add(addend), self.cap)
}

/// Returns the index in the underlying buffer for a given logical element
/// index - subtrahend.
#[inline]
fn wrap_sub(&self, idx: usize, subtrahend: usize) -> usize {
wrap_index(idx.wrapping_sub(subtrahend), self.cap)
}

/// Copies a contiguous block of memory len long from src to dst
#[inline]
unsafe fn copy(&self, dst: usize, src: usize, len: usize) {
Expand Down Expand Up @@ -197,7 +212,7 @@ impl<T> VecDeque<T> {
#[stable(feature = "rust1", since = "1.0.0")]
pub fn get(&self, i: usize) -> Option<&T> {
if i < self.len() {
let idx = self.wrap_index(self.tail + i);
let idx = self.wrap_add(self.tail, i);
unsafe { Some(&*self.ptr.offset(idx as isize)) }
} else {
None
Expand Down Expand Up @@ -227,7 +242,7 @@ impl<T> VecDeque<T> {
#[stable(feature = "rust1", since = "1.0.0")]
pub fn get_mut(&mut self, i: usize) -> Option<&mut T> {
if i < self.len() {
let idx = self.wrap_index(self.tail + i);
let idx = self.wrap_add(self.tail, i);
unsafe { Some(&mut *self.ptr.offset(idx as isize)) }
} else {
None
Expand Down Expand Up @@ -257,8 +272,8 @@ impl<T> VecDeque<T> {
pub fn swap(&mut self, i: usize, j: usize) {
assert!(i < self.len());
assert!(j < self.len());
let ri = self.wrap_index(self.tail + i);
let rj = self.wrap_index(self.tail + j);
let ri = self.wrap_add(self.tail, i);
let rj = self.wrap_add(self.tail, j);
unsafe {
ptr::swap(self.ptr.offset(ri as isize), self.ptr.offset(rj as isize))
}
Expand Down Expand Up @@ -427,7 +442,7 @@ impl<T> VecDeque<T> {
// [. . . o o o o o o o . . . . . . ]
// H T
// [o o . o o o o o ]
let len = self.wrap_index(self.head - target_cap);
let len = self.wrap_sub(self.head, target_cap);
unsafe {
self.copy_nonoverlapping(0, target_cap, len);
}
Expand All @@ -438,7 +453,7 @@ impl<T> VecDeque<T> {
// [o o o o o . . . . . . . . . o o ]
// H T
// [o o o o o . o o ]
debug_assert!(self.wrap_index(self.head - 1) < target_cap);
debug_assert!(self.wrap_sub(self.head, 1) < target_cap);
let len = self.cap - self.tail;
let new_tail = target_cap - len;
unsafe {
Expand Down Expand Up @@ -775,7 +790,7 @@ impl<T> VecDeque<T> {
None
} else {
let tail = self.tail;
self.tail = self.wrap_index(self.tail + 1);
self.tail = self.wrap_add(self.tail, 1);
unsafe { Some(self.buffer_read(tail)) }
}
}
Expand All @@ -799,7 +814,7 @@ impl<T> VecDeque<T> {
debug_assert!(!self.is_full());
}

self.tail = self.wrap_index(self.tail - 1);
self.tail = self.wrap_sub(self.tail, 1);
let tail = self.tail;
unsafe { self.buffer_write(tail, t); }
}
Expand All @@ -824,7 +839,7 @@ impl<T> VecDeque<T> {
}

let head = self.head;
self.head = self.wrap_index(self.head + 1);
self.head = self.wrap_add(self.head, 1);
unsafe { self.buffer_write(head, t) }
}

Expand All @@ -847,7 +862,7 @@ impl<T> VecDeque<T> {
if self.is_empty() {
None
} else {
self.head = self.wrap_index(self.head - 1);
self.head = self.wrap_sub(self.head, 1);
let head = self.head;
unsafe { Some(self.buffer_read(head)) }
}
Expand Down Expand Up @@ -971,7 +986,7 @@ impl<T> VecDeque<T> {
// A - The element that should be after the insertion point
// M - Indicates element was moved

let idx = self.wrap_index(self.tail + i);
let idx = self.wrap_add(self.tail, i);

let distance_to_tail = i;
let distance_to_head = self.len() - i;
Expand All @@ -990,7 +1005,7 @@ impl<T> VecDeque<T> {
// [A o o o o o o o . . . . . I]
//

self.tail = self.wrap_index(self.tail - 1);
self.tail = self.wrap_sub(self.tail, 1);
},
(true, true, _) => unsafe {
// contiguous, insert closer to tail:
Expand All @@ -1012,7 +1027,7 @@ impl<T> VecDeque<T> {
// [o I A o o o o o . . . . . . . o]
// M M

let new_tail = self.wrap_index(self.tail - 1);
let new_tail = self.wrap_sub(self.tail, 1);

self.copy(new_tail, self.tail, 1);
// Already moved the tail, so we only copy `i - 1` elements.
Expand All @@ -1031,7 +1046,7 @@ impl<T> VecDeque<T> {
// M M M

self.copy(idx + 1, idx, self.head - idx);
self.head = self.wrap_index(self.head + 1);
self.head = self.wrap_add(self.head, 1);
},
(false, true, true) => unsafe {
// discontiguous, insert closer to tail, tail section:
Expand Down Expand Up @@ -1123,7 +1138,7 @@ impl<T> VecDeque<T> {
}

// tail might've been changed so we need to recalculate
let new_idx = self.wrap_index(self.tail + i);
let new_idx = self.wrap_add(self.tail, i);
unsafe {
self.buffer_write(new_idx, t);
}
Expand Down Expand Up @@ -1170,7 +1185,7 @@ impl<T> VecDeque<T> {
// R - Indicates element that is being removed
// M - Indicates element was moved

let idx = self.wrap_index(self.tail + i);
let idx = self.wrap_add(self.tail, i);

let elem = unsafe {
Some(self.buffer_read(idx))
Expand Down Expand Up @@ -1219,7 +1234,7 @@ impl<T> VecDeque<T> {
// M M

self.copy(self.tail + 1, self.tail, i);
self.tail = self.wrap_index(self.tail + 1);
self.tail = self.wrap_add(self.tail, 1);
},
(false, false, false) => unsafe {
// discontiguous, remove closer to head, head section:
Expand Down Expand Up @@ -1265,7 +1280,7 @@ impl<T> VecDeque<T> {
self.copy(0, 1, self.head - 1);
}

self.head = self.wrap_index(self.head - 1);
self.head = self.wrap_sub(self.head, 1);
},
(false, true, false) => unsafe {
// discontiguous, remove closer to tail, head section:
Expand All @@ -1286,7 +1301,7 @@ impl<T> VecDeque<T> {
// move elements from tail to end forward, excluding the last one
self.copy(self.tail + 1, self.tail, self.cap - self.tail - 1);

self.tail = self.wrap_index(self.tail + 1);
self.tail = self.wrap_add(self.tail, 1);
}
}

Expand Down Expand Up @@ -1354,7 +1369,7 @@ impl<T> VecDeque<T> {
}

// Cleanup where the ends of the buffers are
self.head = self.wrap_index(self.head - other_len);
self.head = self.wrap_sub(self.head, other_len);
other.head = other.wrap_index(other_len);

other
Expand Down Expand Up @@ -1429,7 +1444,7 @@ fn wrap_index(index: usize, size: usize) -> usize {
#[inline]
fn count(tail: usize, head: usize, size: usize) -> usize {
// size is always a power of 2
(head - tail) & (size - 1)
(head.wrapping_sub(tail)) & (size - 1)
}

/// `VecDeque` iterator.
Expand Down Expand Up @@ -1461,7 +1476,7 @@ impl<'a, T> Iterator for Iter<'a, T> {
return None;
}
let tail = self.tail;
self.tail = wrap_index(self.tail + 1, self.ring.len());
self.tail = wrap_index(self.tail.wrapping_add(1), self.ring.len());
unsafe { Some(self.ring.get_unchecked(tail)) }
}

Expand All @@ -1479,7 +1494,7 @@ impl<'a, T> DoubleEndedIterator for Iter<'a, T> {
if self.tail == self.head {
return None;
}
self.head = wrap_index(self.head - 1, self.ring.len());
self.head = wrap_index(self.head.wrapping_sub(1), self.ring.len());
unsafe { Some(self.ring.get_unchecked(self.head)) }
}
}
Expand All @@ -1500,7 +1515,7 @@ impl<'a, T> RandomAccessIterator for Iter<'a, T> {
if j >= self.indexable() {
None
} else {
let idx = wrap_index(self.tail + j, self.ring.len());
let idx = wrap_index(self.tail.wrapping_add(j), self.ring.len());
unsafe { Some(self.ring.get_unchecked(idx)) }
}
}
Expand All @@ -1524,7 +1539,7 @@ impl<'a, T> Iterator for IterMut<'a, T> {
return None;
}
let tail = self.tail;
self.tail = wrap_index(self.tail + 1, self.ring.len());
self.tail = wrap_index(self.tail.wrapping_add(1), self.ring.len());

unsafe {
let elem = self.ring.get_unchecked_mut(tail);
Expand All @@ -1546,7 +1561,7 @@ impl<'a, T> DoubleEndedIterator for IterMut<'a, T> {
if self.tail == self.head {
return None;
}
self.head = wrap_index(self.head - 1, self.ring.len());
self.head = wrap_index(self.head.wrapping_sub(1), self.ring.len());

unsafe {
let elem = self.ring.get_unchecked_mut(self.head);
Expand Down
12 changes: 6 additions & 6 deletions src/libcore/hash/sip.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@

use prelude::*;
use default::Default;

use num::wrapping::WrappingOps;
use super::Hasher;

/// An implementation of SipHash 2-4.
Expand Down Expand Up @@ -71,17 +71,17 @@ macro_rules! u8to64_le {

macro_rules! rotl {
($x:expr, $b:expr) =>
(($x << $b) | ($x >> (64 - $b)))
(($x << $b) | ($x >> (64.wrapping_sub($b))))
}

macro_rules! compress {
($v0:expr, $v1:expr, $v2:expr, $v3:expr) =>
({
$v0 += $v1; $v1 = rotl!($v1, 13); $v1 ^= $v0;
$v0 = $v0.wrapping_add($v1); $v1 = rotl!($v1, 13); $v1 ^= $v0;
$v0 = rotl!($v0, 32);
$v2 += $v3; $v3 = rotl!($v3, 16); $v3 ^= $v2;
$v0 += $v3; $v3 = rotl!($v3, 21); $v3 ^= $v0;
$v2 += $v1; $v1 = rotl!($v1, 17); $v1 ^= $v2;
$v2 = $v2.wrapping_add($v3); $v3 = rotl!($v3, 16); $v3 ^= $v2;
$v0 = $v0.wrapping_add($v3); $v3 = rotl!($v3, 21); $v3 ^= $v0;
$v2 = $v2.wrapping_add($v1); $v1 = rotl!($v1, 17); $v1 ^= $v2;
$v2 = rotl!($v2, 32);
})
}
Expand Down
11 changes: 11 additions & 0 deletions src/libcore/intrinsics.rs
Original file line number Diff line number Diff line change
Expand Up @@ -546,3 +546,14 @@ extern "rust-intrinsic" {
/// Performs checked `u64` multiplication.
pub fn u64_mul_with_overflow(x: u64, y: u64) -> (u64, bool);
}

// SNAP 880fb89
#[cfg(not(stage0))]
extern "rust-intrinsic" {
/// Returns (a + b) mod 2^N, where N is the width of N in bits.
pub fn overflowing_add<T>(a: T, b: T) -> T;
/// Returns (a - b) mod 2^N, where N is the width of N in bits.
pub fn overflowing_sub<T>(a: T, b: T) -> T;
/// Returns (a * b) mod 2^N, where N is the width of N in bits.
pub fn overflowing_mul<T>(a: T, b: T) -> T;
}
Loading