]> git.lizzy.rs Git - rust.git/commitdiff
Add `core::num::wrapping` and fix overflow errors.
authorJames Miller <james@aatch.net>
Fri, 9 Jan 2015 03:10:57 +0000 (16:10 +1300)
committerFelix S. Klock II <pnkfelix@pnkfx.org>
Tue, 3 Mar 2015 11:10:19 +0000 (12:10 +0100)
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>.

19 files changed:
src/libcollections/bit.rs
src/libcore/hash/sip.rs
src/libcore/num/mod.rs
src/libcore/num/wrapping.rs [new file with mode: 0644]
src/libcore/str/mod.rs
src/librand/distributions/range.rs
src/librand/isaac.rs
src/librustc/metadata/decoder.rs
src/librustc/metadata/encoder.rs
src/librustc/middle/astencode.rs
src/librustc/middle/ty.rs
src/librustc/util/nodemap.rs
src/librustc_back/sha2.rs
src/librustc_typeck/check/mod.rs
src/libstd/collections/hash/map.rs
src/libstd/collections/hash/table.rs
src/libstd/num/mod.rs
src/libstd/prelude/v1.rs
src/libsyntax/ext/deriving/encodable.rs

index a92eccce142b1877095519d4c08ebcb8d90f1161..05bf5f8e42cef4f6296b23afc187eeba5482b2ae 100644 (file)
@@ -818,11 +818,11 @@ pub fn grow(&mut self, n: usize, value: bool) {
         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.
             }
@@ -830,7 +830,7 @@ pub fn grow(&mut self, n: usize, value: bool) {
 
         // 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;
         }
 
index 39bcbacdff182c23b137037d007099a58ca17ed8..df0008c500b8e86d94597c81bfe47d0f2d2956dc 100644 (file)
@@ -14,7 +14,7 @@
 
 use prelude::*;
 use default::Default;
-
+use num::wrapping::WrappingOps;
 use super::Hasher;
 
 /// An implementation of SipHash 2-4.
@@ -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);
     })
 }
index d77a1eb4203c6b4bf786a6c5c6c93f29537c75ba..3ed059520b12f074aa40e01f524dc2d03cc18a3a 100644 (file)
@@ -30,6 +30,9 @@
 use result::Result::{self, Ok, Err};
 use str::{FromStr, StrExt};
 
+#[unstable(feature = "core", reason = "may be removed or relocated")]
+pub mod wrapping;
+
 /// A built-in signed or unsigned integer.
 #[stable(feature = "rust1", since = "1.0.0")]
 pub trait Int
diff --git a/src/libcore/num/wrapping.rs b/src/libcore/num/wrapping.rs
new file mode 100644 (file)
index 0000000..30478a8
--- /dev/null
@@ -0,0 +1,153 @@
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+#![allow(missing_docs)]
+
+use ops::*;
+
+#[cfg(not(stage0))]
+use intrinsics::{overflowing_add, overflowing_sub, overflowing_mul};
+
+pub trait WrappingOps {
+    fn wrapping_add(self, rhs: Self) -> Self;
+    fn wrapping_sub(self, rhs: Self) -> Self;
+    fn wrapping_mul(self, rhs: Self) -> Self;
+}
+
+#[cfg(not(stage0))]
+macro_rules! wrapping_impl {
+    ($($t:ty)*) => ($(
+        impl WrappingOps for $t {
+            #[inline(always)]
+            fn wrapping_add(self, rhs: $t) -> $t {
+                unsafe {
+                    overflowing_add(self, rhs)
+                }
+            }
+            #[inline(always)]
+            fn wrapping_sub(self, rhs: $t) -> $t {
+                unsafe {
+                    overflowing_sub(self, rhs)
+                }
+            }
+            #[inline(always)]
+            fn wrapping_mul(self, rhs: $t) -> $t {
+                unsafe {
+                    overflowing_mul(self, rhs)
+                }
+            }
+        }
+    )*)
+}
+
+#[cfg(stage0)]
+macro_rules! wrapping_impl {
+    ($($t:ty)*) => ($(
+        impl WrappingOps for $t {
+            #[inline(always)]
+            fn wrapping_add(self, rhs: $t) -> $t {
+                self + rhs
+            }
+            #[inline(always)]
+            fn wrapping_sub(self, rhs: $t) -> $t {
+                self - rhs
+            }
+            #[inline(always)]
+            fn wrapping_mul(self, rhs: $t) -> $t {
+                self * rhs
+            }
+        }
+    )*)
+}
+
+wrapping_impl! { uint u8 u16 u32 u64 int i8 i16 i32 i64 }
+
+#[unstable(feature = "core", reason = "may be removed, renamed, or relocated")]
+#[derive(PartialEq,Eq,PartialOrd,Ord,Clone,Copy)]
+pub struct Wrapping<T>(pub T);
+
+impl<T:WrappingOps> Add for Wrapping<T> {
+    type Output = Wrapping<T>;
+
+    #[inline(always)]
+    fn add(self, other: Wrapping<T>) -> Wrapping<T> {
+        Wrapping(self.0.wrapping_add(other.0))
+    }
+}
+
+impl<T:WrappingOps> Sub for Wrapping<T> {
+    type Output = Wrapping<T>;
+
+    #[inline(always)]
+    fn sub(self, other: Wrapping<T>) -> Wrapping<T> {
+        Wrapping(self.0.wrapping_sub(other.0))
+    }
+}
+
+impl<T:WrappingOps> Mul for Wrapping<T> {
+    type Output = Wrapping<T>;
+
+    #[inline(always)]
+    fn mul(self, other: Wrapping<T>) -> Wrapping<T> {
+        Wrapping(self.0.wrapping_mul(other.0))
+    }
+}
+
+impl<T:WrappingOps+Not<Output=T>> Not for Wrapping<T> {
+    type Output = Wrapping<T>;
+
+    fn not(self) -> Wrapping<T> {
+        Wrapping(!self.0)
+    }
+}
+
+impl<T:WrappingOps+BitXor<Output=T>> BitXor for Wrapping<T> {
+    type Output = Wrapping<T>;
+
+    #[inline(always)]
+    fn bitxor(self, other: Wrapping<T>) -> Wrapping<T> {
+        Wrapping(self.0 ^ other.0)
+    }
+}
+
+impl<T:WrappingOps+BitOr<Output=T>> BitOr for Wrapping<T> {
+    type Output = Wrapping<T>;
+
+    #[inline(always)]
+    fn bitor(self, other: Wrapping<T>) -> Wrapping<T> {
+        Wrapping(self.0 | other.0)
+    }
+}
+
+impl<T:WrappingOps+BitAnd<Output=T>> BitAnd for Wrapping<T> {
+    type Output = Wrapping<T>;
+
+    #[inline(always)]
+    fn bitand(self, other: Wrapping<T>) -> Wrapping<T> {
+        Wrapping(self.0 & other.0)
+    }
+}
+
+impl<T:WrappingOps+Shl<uint,Output=T>> Shl<uint> for Wrapping<T> {
+    type Output = Wrapping<T>;
+
+    #[inline(always)]
+    fn shl(self, other: uint) -> Wrapping<T> {
+        Wrapping(self.0 << other)
+    }
+}
+
+impl<T:WrappingOps+Shr<uint,Output=T>> Shr<uint> for Wrapping<T> {
+    type Output = Wrapping<T>;
+
+    #[inline(always)]
+    fn shr(self, other: uint) -> Wrapping<T> {
+        Wrapping(self.0 >> other)
+    }
+}
index b354116993c23a1e750be1fa8c900dc95261ab85..a7a0690640921210bb6d7ae797320639e510727b 100644 (file)
@@ -830,6 +830,7 @@ fn next(&mut self, haystack: &[u8], needle: &[u8], long_period: bool)
     #[inline]
     #[allow(dead_code)]
     fn maximal_suffix(arr: &[u8], reversed: bool) -> (usize, usize) {
+        use num::wrapping::WrappingOps;
         let mut left = -1; // Corresponds to i in the paper
         let mut right = 0; // Corresponds to j in the paper
         let mut offset = 1; // Corresponds to k in the paper
@@ -839,17 +840,17 @@ fn maximal_suffix(arr: &[u8], reversed: bool) -> (usize, usize) {
             let a;
             let b;
             if reversed {
-                a = arr[left + offset];
+                a = arr[left.wrapping_add(offset)];
                 b = arr[right + offset];
             } else {
                 a = arr[right + offset];
-                b = arr[left + offset];
+                b = arr[left.wrapping_add(offset)];
             }
             if a < b {
                 // Suffix is smaller, period is entire prefix so far.
                 right += offset;
                 offset = 1;
-                period = right - left;
+                period = right.wrapping_sub(left);
             } else if a == b {
                 // Advance through repetition of the current period.
                 if offset == period {
@@ -866,7 +867,7 @@ fn maximal_suffix(arr: &[u8], reversed: bool) -> (usize, usize) {
                 period = 1;
             }
         }
-        (left + 1, period)
+        (left.wrapping_add(1), period)
     }
 }
 
index 6eb1d68a081aa9d48632a383bfe0315d7f994214..04c67b16a7c59a1533431dba06ab331c84a7900c 100644 (file)
@@ -14,6 +14,7 @@
 
 use core::prelude::{PartialOrd};
 use core::num::Int;
+use core::num::wrapping::WrappingOps;
 
 use Rng;
 use distributions::{Sample, IndependentSample};
@@ -97,7 +98,7 @@ impl SampleRange for $ty {
             // bijection.
 
             fn construct_range(low: $ty, high: $ty) -> Range<$ty> {
-                let range = high as $unsigned - low as $unsigned;
+                let range = (high as $unsigned).wrapping_sub(low as $unsigned);
                 let unsigned_max: $unsigned = Int::max_value();
 
                 // this is the largest number that fits into $unsigned
index 701749ff3443f6e0280ad1308001854ea645cfe2..63eb8417655ee14608e52d1536c2019dfec897bf 100644 (file)
@@ -304,7 +304,7 @@ pub fn new_unseeded() -> Isaac64Rng {
     fn init(&mut self, use_rsl: bool) {
         macro_rules! init {
             ($var:ident) => (
-                let mut $var = 0x9e3779b97f4a7c13;
+                let mut $var = Wrapping(0x9e3779b97f4a7c13);
             )
         }
         init!(a); init!(b); init!(c); init!(d);
@@ -312,14 +312,14 @@ macro_rules! init {
 
         macro_rules! mix {
             () => {{
-                a-=e; f^=h>>9;  h+=a;
-                b-=f; g^=a<<9;  a+=b;
-                c-=g; h^=b>>23; b+=c;
-                d-=h; a^=c<<15; c+=d;
-                e-=a; b^=d>>14; d+=e;
-                f-=b; c^=e<<20; e+=f;
-                g-=c; d^=f>>17; f+=g;
-                h-=d; e^=g<<14; g+=h;
+                a=a-e; f=f^h>>9;  h=h+a;
+                b=b-f; g=g^a<<9;  a=a+b;
+                c=c-g; h=h^b>>23; b=b+c;
+                d=d-h; a=a^c<<15; c=c+d;
+                e=e-a; b=b^d>>14; d=d+e;
+                f=f-b; c=c^e<<20; e=e+f;
+                g=g-c; d=d^f>>17; f=f+g;
+                h=h-d; e=e^g<<14; g=g+h;
             }}
         }
 
@@ -331,15 +331,15 @@ macro_rules! mix {
             macro_rules! memloop {
                 ($arr:expr) => {{
                     for i in (0..RAND_SIZE_64 / 8).map(|i| i * 8) {
-                        a+=$arr[i  ]; b+=$arr[i+1];
-                        c+=$arr[i+2]; d+=$arr[i+3];
-                        e+=$arr[i+4]; f+=$arr[i+5];
-                        g+=$arr[i+6]; h+=$arr[i+7];
+                        a=a+Wrapping($arr[i  ]); b=b+Wrapping($arr[i+1]);
+                        c=c+Wrapping($arr[i+2]); d=d+Wrapping($arr[i+3]);
+                        e=e+Wrapping($arr[i+4]); f=f+Wrapping($arr[i+5]);
+                        g=g+Wrapping($arr[i+6]); h=h+Wrapping($arr[i+7]);
                         mix!();
-                        self.mem[i  ]=a; self.mem[i+1]=b;
-                        self.mem[i+2]=c; self.mem[i+3]=d;
-                        self.mem[i+4]=e; self.mem[i+5]=f;
-                        self.mem[i+6]=g; self.mem[i+7]=h;
+                        self.mem[i  ]=a.0; self.mem[i+1]=b.0;
+                        self.mem[i+2]=c.0; self.mem[i+3]=d.0;
+                        self.mem[i+4]=e.0; self.mem[i+5]=f.0;
+                        self.mem[i+6]=g.0; self.mem[i+7]=h.0;
                     }
                 }}
             }
@@ -349,10 +349,10 @@ macro_rules! memloop {
         } else {
             for i in (0..RAND_SIZE_64 / 8).map(|i| i * 8) {
                 mix!();
-                self.mem[i  ]=a; self.mem[i+1]=b;
-                self.mem[i+2]=c; self.mem[i+3]=d;
-                self.mem[i+4]=e; self.mem[i+5]=f;
-                self.mem[i+6]=g; self.mem[i+7]=h;
+                self.mem[i  ]=a.0; self.mem[i+1]=b.0;
+                self.mem[i+2]=c.0; self.mem[i+3]=d.0;
+                self.mem[i+4]=e.0; self.mem[i+5]=f.0;
+                self.mem[i+6]=g.0; self.mem[i+7]=h.0;
             }
         }
 
@@ -363,8 +363,8 @@ macro_rules! memloop {
     fn isaac64(&mut self) {
         self.c += 1;
         // abbreviations
-        let mut a = self.a;
-        let mut b = self.b + self.c;
+        let mut a = Wrapping(self.a);
+        let mut b = Wrapping(self.b) + Wrapping(self.c);
         const MIDPOINT: uint =  RAND_SIZE_64 / 2;
         const MP_VEC: [(uint, uint); 2] = [(0,MIDPOINT), (MIDPOINT, 0)];
         macro_rules! ind {
@@ -383,13 +383,13 @@ macro_rules! rngstepp {
                         let mix = if $j == 0 {!mix} else {mix};
 
                         unsafe {
-                            let x = *self.mem.get_unchecked(base + mr_offset);
-                            a = mix + *self.mem.get_unchecked(base + m2_offset);
-                            let y = ind!(x) + a + b;
-                            *self.mem.get_unchecked_mut(base + mr_offset) = y;
+                            let x = Wrapping(*self.mem.get_unchecked(base + mr_offset));
+                            a = mix + Wrapping(*self.mem.get_unchecked(base + m2_offset));
+                            let y = Wrapping(ind!(x.0)) + a + b;
+                            *self.mem.get_unchecked_mut(base + mr_offset) = y.0;
 
-                            b = ind!(y >> RAND_SIZE_64_LEN) + x;
-                            *self.rsl.get_unchecked_mut(base + mr_offset) = b;
+                            b = Wrapping(ind!(y.0 >> RAND_SIZE_64_LEN)) + x;
+                            *self.rsl.get_unchecked_mut(base + mr_offset) = b.0;
                         }
                     }}
                 }
@@ -401,13 +401,13 @@ macro_rules! rngstepn {
                         let mix = if $j == 0 {!mix} else {mix};
 
                         unsafe {
-                            let x = *self.mem.get_unchecked(base + mr_offset);
-                            a = mix + *self.mem.get_unchecked(base + m2_offset);
-                            let y = ind!(x) + a + b;
-                            *self.mem.get_unchecked_mut(base + mr_offset) = y;
+                            let x = Wrapping(*self.mem.get_unchecked(base + mr_offset));
+                            a = mix + Wrapping(*self.mem.get_unchecked(base + m2_offset));
+                            let y = Wrapping(ind!(x.0)) + a + b;
+                            *self.mem.get_unchecked_mut(base + mr_offset) = y.0;
 
-                            b = ind!(y >> RAND_SIZE_64_LEN) + x;
-                            *self.rsl.get_unchecked_mut(base + mr_offset) = b;
+                            b = Wrapping(ind!(y.0 >> RAND_SIZE_64_LEN)) + x;
+                            *self.rsl.get_unchecked_mut(base + mr_offset) = b.0;
                         }
                     }}
                 }
@@ -419,8 +419,8 @@ macro_rules! rngstepn {
             }
         }
 
-        self.a = a;
-        self.b = b;
+        self.a = a.0;
+        self.b = b.0;
         self.cnt = RAND_SIZE_64;
     }
 }
index 251c5e6eac70ebe7df5530dca754089ebb442a0b..e32fcaec04734b49730de759492641242d8449fc 100644 (file)
@@ -783,7 +783,7 @@ pub fn get_enum_variants<'tcx>(intr: Rc<IdentInterner>, cdata: Cmd, id: ast::Nod
             _         => { /* empty */ }
         }
         let old_disr_val = disr_val;
-        disr_val += 1;
+        disr_val = disr_val.wrapping_add(1);
         Rc::new(ty::VariantInfo {
             args: arg_tys,
             arg_names: arg_names,
index 131a299cc500fc9af6e4fd5ad050be88e6b274c4..8152a2bf16dd1f773a56d949ef14dfd587dfcecd 100644 (file)
@@ -347,7 +347,7 @@ fn encode_enum_variant_info(ecx: &EncodeContext,
 
         ecx.tcx.map.with_path(variant.node.id, |path| encode_path(rbml_w, path));
         rbml_w.end_tag();
-        disr_val += 1;
+        disr_val = disr_val.wrapping_add(1);
         i += 1;
     }
 }
index 599dde4b70155affa34456593f110b4f4f1675e3..33c0fb8b031ef4e8c05a8c6c414b244fd1b8955d 100644 (file)
@@ -204,7 +204,9 @@ impl<'a, 'b, 'tcx> DecodeContext<'a, 'b, 'tcx> {
     pub fn tr_id(&self, id: ast::NodeId) -> ast::NodeId {
         // from_id_range should be non-empty
         assert!(!self.from_id_range.empty());
-        (id - self.from_id_range.min + self.to_id_range.min)
+        // Use wrapping arithmetic because otherwise it introduces control flow.
+        // Maybe we should just have the control flow? -- aatch
+        (id.wrapping_sub(self.from_id_range.min).wrapping_add(self.to_id_range.min))
     }
 
     /// Translates an EXTERNAL def-id, converting the crate number from the one used in the encoded
index aaba840825e69ea23248efe10c6c47d9f96f88a4..b6d1fc5a3694856140f9e64f5711562e806260a2 100644 (file)
@@ -5333,6 +5333,7 @@ pub fn type_is_empty(cx: &ctxt, ty: Ty) -> bool {
 
 pub fn enum_variants<'tcx>(cx: &ctxt<'tcx>, id: ast::DefId)
                            -> Rc<Vec<Rc<VariantInfo<'tcx>>>> {
+    use std::num::Int; // For checked_add
     memoized(&cx.enum_var_cache, id, |id: ast::DefId| {
         if ast::LOCAL_CRATE != id.krate {
             Rc::new(csearch::get_enum_variants(cx, id))
@@ -5349,11 +5350,7 @@ pub fn enum_variants<'tcx>(cx: &ctxt<'tcx>, id: ast::DefId)
                             let mut last_discriminant: Option<Disr> = None;
                             Rc::new(enum_definition.variants.iter().map(|variant| {
 
-                                let mut discriminant = match last_discriminant {
-                                    Some(val) => val + 1,
-                                    None => INITIAL_DISCRIMINANT_VALUE
-                                };
-
+                                let mut discriminant = INITIAL_DISCRIMINANT_VALUE;
                                 if let Some(ref e) = variant.node.disr_expr {
                                     // Preserve all values, and prefer signed.
                                     let ty = Some(cx.types.i64);
@@ -5373,7 +5370,19 @@ pub fn enum_variants<'tcx>(cx: &ctxt<'tcx>, id: ast::DefId)
                                                       "expected constant: {}", err);
                                         }
                                     }
-                                };
+                                } else {
+                                    if let Some(val) = last_discriminant {
+                                        if let Some(v) = val.checked_add(1) {
+                                            discriminant = v
+                                        } else {
+                                            cx.sess.span_err(
+                                                variant.span,
+                                                &format!("Discriminant overflowed!"));
+                                        }
+                                    } else {
+                                        discriminant = INITIAL_DISCRIMINANT_VALUE;
+                                    }
+                                }
 
                                 last_discriminant = Some(discriminant);
                                 Rc::new(VariantInfo::from_ast_variant(cx, &**variant,
index b15da7dab3ee606627f78d4d53618fa47e55dfd8..0f69aa941a31e67b51080dd3051068f5f5362aee 100644 (file)
@@ -57,7 +57,7 @@ fn write(&mut self, bytes: &[u8]) {
         let FnvHasher(mut hash) = *self;
         for byte in bytes {
             hash = hash ^ (*byte as u64);
-            hash = hash * 0x100000001b3;
+            hash = hash.wrapping_mul(0x100000001b3);
         }
         *self = FnvHasher(hash);
     }
index 6654a46f7c31b51cdaee38add94af4f904eb793e..8acb6851f111d752e4755a15afeb9267a6bff913 100644 (file)
@@ -347,17 +347,19 @@ fn sigma1(x: u32) -> u32 {
         // Sha-512 and Sha-256 use basically the same calculations which are implemented
         // by these macros. Inlining the calculations seems to result in better generated code.
         macro_rules! schedule_round { ($t:expr) => (
-                w[$t] = sigma1(w[$t - 2]) + w[$t - 7] + sigma0(w[$t - 15]) + w[$t - 16];
-                )
+            w[$t] = sigma1(w[$t - 2]).wrapping_add(w[$t - 7])
+                .wrapping_add(sigma0(w[$t - 15])).wrapping_add(w[$t - 16]);
+            )
         }
 
         macro_rules! sha2_round {
             ($A:ident, $B:ident, $C:ident, $D:ident,
              $E:ident, $F:ident, $G:ident, $H:ident, $K:ident, $t:expr) => (
                 {
-                    $H += sum1($E) + ch($E, $F, $G) + $K[$t] + w[$t];
-                    $D += $H;
-                    $H += sum0($A) + maj($A, $B, $C);
+                    $H = $H.wrapping_add(sum1($E)).wrapping_add(ch($E, $F, $G))
+                        .wrapping_add($K[$t]).wrapping_add(w[$t]);
+                    $D = $D.wrapping_add($H);
+                    $H = $H.wrapping_add(sum0($A)).wrapping_add(maj($A, $B, $C));
                 }
              )
         }
@@ -397,14 +399,14 @@ macro_rules! sha2_round {
             sha2_round!(b, c, d, e, f, g, h, a, K32, t + 7);
         }
 
-        self.h0 += a;
-        self.h1 += b;
-        self.h2 += c;
-        self.h3 += d;
-        self.h4 += e;
-        self.h5 += f;
-        self.h6 += g;
-        self.h7 += h;
+        self.h0 = self.h0.wrapping_add(a);
+        self.h1 = self.h1.wrapping_add(b);
+        self.h2 = self.h2.wrapping_add(c);
+        self.h3 = self.h3.wrapping_add(d);
+        self.h4 = self.h4.wrapping_add(e);
+        self.h5 = self.h5.wrapping_add(f);
+        self.h6 = self.h6.wrapping_add(g);
+        self.h7 = self.h7.wrapping_add(h);
     }
 }
 
index 273aadc383c6934bf8e87923a700f4499f1b7deb..10771935e22a4b274b5a87ecf9a45f8fb82610ad 100644 (file)
@@ -4554,6 +4554,7 @@ fn do_check<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
                           id: ast::NodeId,
                           hint: attr::ReprAttr)
                           -> Vec<Rc<ty::VariantInfo<'tcx>>> {
+        use std::num::Int;
 
         let rty = ty::node_id_to_type(ccx.tcx, id);
         let mut variants: Vec<Rc<ty::VariantInfo>> = Vec::new();
@@ -4565,7 +4566,13 @@ fn do_check<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
             // If the discriminant value is specified explicitly in the enum check whether the
             // initialization expression is valid, otherwise use the last value plus one.
             let mut current_disr_val = match prev_disr_val {
-                Some(prev_disr_val) => prev_disr_val + 1,
+                Some(prev_disr_val) => {
+                    if let Some(v) = prev_disr_val.checked_add(1) {
+                        v
+                    } else {
+                        ty::INITIAL_DISCRIMINANT_VALUE
+                    }
+                }
                 None => ty::INITIAL_DISCRIMINANT_VALUE
             };
 
index faddbba50590f9ce1a87499ef7db2a299e21b038..8eb29a8327a52710c6479f026e35bc4a698b516e 100644 (file)
@@ -314,6 +314,13 @@ fn search_hashed<K, V, M, F>(table: M,
     M: Deref<Target=RawTable<K, V>>,
     F: FnMut(&K) -> bool,
 {
+    // This is the only function where capacity can be zero. To avoid
+    // undefined behaviour when Bucket::new gets the raw bucket in this
+    // case, immediately return the appropriate search result.
+    if table.capacity() == 0 {
+        return TableRef(table);
+    }
+
     let size = table.size();
     let mut probe = Bucket::new(table, hash);
     let ib = probe.index();
index 4c03d8915eb8a04ca0909e022739eb6c38ade22a..908b5267b69d67be1673413c8c0f559ad7de83b9 100644 (file)
@@ -224,6 +224,9 @@ pub fn new(table: M, hash: SafeHash) -> Bucket<K, V, M> {
     }
 
     pub fn at_index(table: M, ib_index: usize) -> Bucket<K, V, M> {
+        // if capacity is 0, then the RawBucket will be populated with bogus pointers.
+        // This is an uncommon case though, so avoid it in release builds.
+        debug_assert!(table.capacity() > 0, "Table should have capacity at this point");
         let ib_index = ib_index & (table.capacity() - 1);
         Bucket {
             raw: unsafe {
@@ -368,10 +371,11 @@ pub fn into_bucket(self) -> Bucket<K, V, M> {
     /// In the cited blog posts above, this is called the "distance to
     /// initial bucket", or DIB. Also known as "probe count".
     pub fn distance(&self) -> usize {
+        use core::num::wrapping::WrappingOps;
         // Calculates the distance one has to travel when going from
         // `hash mod capacity` onwards to `idx mod capacity`, wrapping around
         // if the destination is not reached before the end of the table.
-        (self.idx - self.hash().inspect() as usize) & (self.table.capacity() - 1)
+        (self.idx.wrapping_sub(self.hash().inspect() as usize)) & (self.table.capacity() - 1)
     }
 
     #[inline]
index d776079efaeeccd00b8cda8e8a180ba26bf3145c..d4428282b148e3d16398dc883daf903bac6c74df 100644 (file)
@@ -30,6 +30,7 @@
 pub use core::num::{from_f32, from_f64};
 pub use core::num::{FromStrRadix, from_str_radix};
 pub use core::num::{FpCategory, ParseIntError, ParseFloatError};
+pub use core::num::wrapping;
 
 use option::Option;
 
index dad0ff0a15e299424d265b076d15f20f229c525b..60e1354482c8f4626eb1872e3a5fb909afe65cf4 100644 (file)
@@ -58,3 +58,5 @@
 #[doc(no_inline)] pub use old_io::{Buffer, Writer, Reader, Seek, BufferPrelude};
 // NB: remove when range syntax lands
 #[doc(no_inline)] pub use iter::range;
+
+#[doc(no_inline)] pub use num::wrapping::{Wrapping, WrappingOps};
index 8038074cee14fbe3473da0f0ce5997bbb6a9b800..94b7d1b4d8cb0658c115a2daf86ab2c32298bbd6 100644 (file)
@@ -240,25 +240,24 @@ fn encodable_substructure(cx: &mut ExtCtxt, trait_span: Span,
             let encoder = cx.expr_ident(trait_span, blkarg);
             let emit_variant_arg = cx.ident_of("emit_enum_variant_arg");
             let mut stmts = Vec::new();
-            let last = fields.len() - 1;
-            for (i, &FieldInfo { ref self_, span, .. }) in fields.iter().enumerate() {
-                let enc = cx.expr_method_call(span, self_.clone(),
-                                              encode, vec!(blkencoder.clone()));
-                let lambda = cx.lambda_expr_1(span, enc, blkarg);
-                let call = cx.expr_method_call(span, blkencoder.clone(),
-                                               emit_variant_arg,
-                                               vec!(cx.expr_usize(span, i),
-                                                 lambda));
-                let call = if i != last {
-                    cx.expr_try(span, call)
-                } else {
-                    cx.expr(span, ExprRet(Some(call)))
-                };
-                stmts.push(cx.stmt_expr(call));
-            }
-
-            // enums with no fields need to return Ok()
-            if stmts.len() == 0 {
+            if fields.len() > 0 {
+                let last = fields.len() - 1;
+                for (i, &FieldInfo { ref self_, span, .. }) in fields.iter().enumerate() {
+                    let enc = cx.expr_method_call(span, self_.clone(),
+                                                  encode, vec!(blkencoder.clone()));
+                    let lambda = cx.lambda_expr_1(span, enc, blkarg);
+                    let call = cx.expr_method_call(span, blkencoder.clone(),
+                                                   emit_variant_arg,
+                                                   vec!(cx.expr_usize(span, i),
+                                                        lambda));
+                    let call = if i != last {
+                        cx.expr_try(span, call)
+                    } else {
+                        cx.expr(span, ExprRet(Some(call)))
+                    };
+                    stmts.push(cx.stmt_expr(call));
+                }
+            } else {
                 let ret_ok = cx.expr(trait_span,
                                      ExprRet(Some(cx.expr_ok(trait_span,
                                                              cx.expr_tuple(trait_span, vec![])))));