Skip to content

Commit 1246d40

Browse files
Aatchpnkfelix
authored andcommitted
Add core::num::wrapping and fix overflow errors.
Many of the core rust libraries have places that rely on integer wrapping behaviour. These places have been altered to use the wrapping_* methods: * core::hash::sip - A number of macros * core::str - The `maximal_suffix` method in `TwoWaySearcher` * rustc::util::nodemap - Implementation of FnvHash * rustc_back::sha2 - A number of macros and other places * rand::isaac - Isaac64Rng, changed to use the Wrapping helper type Some places had "benign" underflow. This is when underflow or overflow occurs, but the unspecified value is not used due to other conditions. * collections::bit::Bitv - underflow when `self.nbits` is zero. * collections::hash::{map,table} - Underflow when searching an empty table. Did cause undefined behaviour in this case due to an out-of-bounds ptr::offset based on the underflowed index. However the resulting pointers would never be read from. * syntax::ext::deriving::encodable - Underflow when calculating the index of the last field in a variant with no fields. These cases were altered to avoid the underflow, often by moving the underflowing operation to a place where underflow could not happen. There was one case that relied on the fact that unsigned arithmetic and two's complement arithmetic are identical with wrapping semantics. This was changed to use the wrapping_* methods. Finally, the calculation of variant discriminants could overflow if the preceeding discriminant was `U64_MAX`. The logic in `rustc::middle::ty` for this was altered to avoid the overflow completely, while the remaining places were changed to use wrapping methods. This is because `rustc::middle::ty::enum_variants` now throws an error when the calculated discriminant value overflows a `u64`. This behaviour can be triggered by the following code: ``` enum Foo { A = U64_MAX, B } ``` This commit also implements the remaining integer operators for Wrapped<T>.
1 parent cdfff9d commit 1246d40

File tree

19 files changed

+286
-95
lines changed

19 files changed

+286
-95
lines changed

src/libcollections/bit.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -818,19 +818,19 @@ impl BitVec {
818818
let full_value = if value { !0 } else { 0 };
819819

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

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

src/libcore/hash/sip.rs

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414
1515
use prelude::*;
1616
use default::Default;
17-
17+
use num::wrapping::WrappingOps;
1818
use super::Hasher;
1919

2020
/// An implementation of SipHash 2-4.
@@ -71,17 +71,17 @@ macro_rules! u8to64_le {
7171

7272
macro_rules! rotl {
7373
($x:expr, $b:expr) =>
74-
(($x << $b) | ($x >> (64 - $b)))
74+
(($x << $b) | ($x >> (64.wrapping_sub($b))))
7575
}
7676

7777
macro_rules! compress {
7878
($v0:expr, $v1:expr, $v2:expr, $v3:expr) =>
7979
({
80-
$v0 += $v1; $v1 = rotl!($v1, 13); $v1 ^= $v0;
80+
$v0 = $v0.wrapping_add($v1); $v1 = rotl!($v1, 13); $v1 ^= $v0;
8181
$v0 = rotl!($v0, 32);
82-
$v2 += $v3; $v3 = rotl!($v3, 16); $v3 ^= $v2;
83-
$v0 += $v3; $v3 = rotl!($v3, 21); $v3 ^= $v0;
84-
$v2 += $v1; $v1 = rotl!($v1, 17); $v1 ^= $v2;
82+
$v2 = $v2.wrapping_add($v3); $v3 = rotl!($v3, 16); $v3 ^= $v2;
83+
$v0 = $v0.wrapping_add($v3); $v3 = rotl!($v3, 21); $v3 ^= $v0;
84+
$v2 = $v2.wrapping_add($v1); $v1 = rotl!($v1, 17); $v1 ^= $v2;
8585
$v2 = rotl!($v2, 32);
8686
})
8787
}

src/libcore/num/mod.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,9 @@ use option::Option::{self, Some, None};
3030
use result::Result::{self, Ok, Err};
3131
use str::{FromStr, StrExt};
3232

33+
#[unstable(feature = "core", reason = "may be removed or relocated")]
34+
pub mod wrapping;
35+
3336
/// A built-in signed or unsigned integer.
3437
#[stable(feature = "rust1", since = "1.0.0")]
3538
pub trait Int

src/libcore/num/wrapping.rs

Lines changed: 153 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,153 @@
1+
// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
#![allow(missing_docs)]
11+
12+
use ops::*;
13+
14+
#[cfg(not(stage0))]
15+
use intrinsics::{overflowing_add, overflowing_sub, overflowing_mul};
16+
17+
pub trait WrappingOps {
18+
fn wrapping_add(self, rhs: Self) -> Self;
19+
fn wrapping_sub(self, rhs: Self) -> Self;
20+
fn wrapping_mul(self, rhs: Self) -> Self;
21+
}
22+
23+
#[cfg(not(stage0))]
24+
macro_rules! wrapping_impl {
25+
($($t:ty)*) => ($(
26+
impl WrappingOps for $t {
27+
#[inline(always)]
28+
fn wrapping_add(self, rhs: $t) -> $t {
29+
unsafe {
30+
overflowing_add(self, rhs)
31+
}
32+
}
33+
#[inline(always)]
34+
fn wrapping_sub(self, rhs: $t) -> $t {
35+
unsafe {
36+
overflowing_sub(self, rhs)
37+
}
38+
}
39+
#[inline(always)]
40+
fn wrapping_mul(self, rhs: $t) -> $t {
41+
unsafe {
42+
overflowing_mul(self, rhs)
43+
}
44+
}
45+
}
46+
)*)
47+
}
48+
49+
#[cfg(stage0)]
50+
macro_rules! wrapping_impl {
51+
($($t:ty)*) => ($(
52+
impl WrappingOps for $t {
53+
#[inline(always)]
54+
fn wrapping_add(self, rhs: $t) -> $t {
55+
self + rhs
56+
}
57+
#[inline(always)]
58+
fn wrapping_sub(self, rhs: $t) -> $t {
59+
self - rhs
60+
}
61+
#[inline(always)]
62+
fn wrapping_mul(self, rhs: $t) -> $t {
63+
self * rhs
64+
}
65+
}
66+
)*)
67+
}
68+
69+
wrapping_impl! { uint u8 u16 u32 u64 int i8 i16 i32 i64 }
70+
71+
#[unstable(feature = "core", reason = "may be removed, renamed, or relocated")]
72+
#[derive(PartialEq,Eq,PartialOrd,Ord,Clone,Copy)]
73+
pub struct Wrapping<T>(pub T);
74+
75+
impl<T:WrappingOps> Add for Wrapping<T> {
76+
type Output = Wrapping<T>;
77+
78+
#[inline(always)]
79+
fn add(self, other: Wrapping<T>) -> Wrapping<T> {
80+
Wrapping(self.0.wrapping_add(other.0))
81+
}
82+
}
83+
84+
impl<T:WrappingOps> Sub for Wrapping<T> {
85+
type Output = Wrapping<T>;
86+
87+
#[inline(always)]
88+
fn sub(self, other: Wrapping<T>) -> Wrapping<T> {
89+
Wrapping(self.0.wrapping_sub(other.0))
90+
}
91+
}
92+
93+
impl<T:WrappingOps> Mul for Wrapping<T> {
94+
type Output = Wrapping<T>;
95+
96+
#[inline(always)]
97+
fn mul(self, other: Wrapping<T>) -> Wrapping<T> {
98+
Wrapping(self.0.wrapping_mul(other.0))
99+
}
100+
}
101+
102+
impl<T:WrappingOps+Not<Output=T>> Not for Wrapping<T> {
103+
type Output = Wrapping<T>;
104+
105+
fn not(self) -> Wrapping<T> {
106+
Wrapping(!self.0)
107+
}
108+
}
109+
110+
impl<T:WrappingOps+BitXor<Output=T>> BitXor for Wrapping<T> {
111+
type Output = Wrapping<T>;
112+
113+
#[inline(always)]
114+
fn bitxor(self, other: Wrapping<T>) -> Wrapping<T> {
115+
Wrapping(self.0 ^ other.0)
116+
}
117+
}
118+
119+
impl<T:WrappingOps+BitOr<Output=T>> BitOr for Wrapping<T> {
120+
type Output = Wrapping<T>;
121+
122+
#[inline(always)]
123+
fn bitor(self, other: Wrapping<T>) -> Wrapping<T> {
124+
Wrapping(self.0 | other.0)
125+
}
126+
}
127+
128+
impl<T:WrappingOps+BitAnd<Output=T>> BitAnd for Wrapping<T> {
129+
type Output = Wrapping<T>;
130+
131+
#[inline(always)]
132+
fn bitand(self, other: Wrapping<T>) -> Wrapping<T> {
133+
Wrapping(self.0 & other.0)
134+
}
135+
}
136+
137+
impl<T:WrappingOps+Shl<uint,Output=T>> Shl<uint> for Wrapping<T> {
138+
type Output = Wrapping<T>;
139+
140+
#[inline(always)]
141+
fn shl(self, other: uint) -> Wrapping<T> {
142+
Wrapping(self.0 << other)
143+
}
144+
}
145+
146+
impl<T:WrappingOps+Shr<uint,Output=T>> Shr<uint> for Wrapping<T> {
147+
type Output = Wrapping<T>;
148+
149+
#[inline(always)]
150+
fn shr(self, other: uint) -> Wrapping<T> {
151+
Wrapping(self.0 >> other)
152+
}
153+
}

src/libcore/str/mod.rs

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -830,6 +830,7 @@ impl TwoWaySearcher {
830830
#[inline]
831831
#[allow(dead_code)]
832832
fn maximal_suffix(arr: &[u8], reversed: bool) -> (usize, usize) {
833+
use num::wrapping::WrappingOps;
833834
let mut left = -1; // Corresponds to i in the paper
834835
let mut right = 0; // Corresponds to j in the paper
835836
let mut offset = 1; // Corresponds to k in the paper
@@ -839,17 +840,17 @@ impl TwoWaySearcher {
839840
let a;
840841
let b;
841842
if reversed {
842-
a = arr[left + offset];
843+
a = arr[left.wrapping_add(offset)];
843844
b = arr[right + offset];
844845
} else {
845846
a = arr[right + offset];
846-
b = arr[left + offset];
847+
b = arr[left.wrapping_add(offset)];
847848
}
848849
if a < b {
849850
// Suffix is smaller, period is entire prefix so far.
850851
right += offset;
851852
offset = 1;
852-
period = right - left;
853+
period = right.wrapping_sub(left);
853854
} else if a == b {
854855
// Advance through repetition of the current period.
855856
if offset == period {
@@ -866,7 +867,7 @@ impl TwoWaySearcher {
866867
period = 1;
867868
}
868869
}
869-
(left + 1, period)
870+
(left.wrapping_add(1), period)
870871
}
871872
}
872873

src/librand/distributions/range.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414

1515
use core::prelude::{PartialOrd};
1616
use core::num::Int;
17+
use core::num::wrapping::WrappingOps;
1718

1819
use Rng;
1920
use distributions::{Sample, IndependentSample};
@@ -97,7 +98,7 @@ macro_rules! integer_impl {
9798
// bijection.
9899

99100
fn construct_range(low: $ty, high: $ty) -> Range<$ty> {
100-
let range = high as $unsigned - low as $unsigned;
101+
let range = (high as $unsigned).wrapping_sub(low as $unsigned);
101102
let unsigned_max: $unsigned = Int::max_value();
102103

103104
// this is the largest number that fits into $unsigned

0 commit comments

Comments
 (0)