]> git.lizzy.rs Git - rust.git/commitdiff
auto merge of #9010 : aaronlaursen/rust/master, r=alexcrichton
authorbors <bors@rust-lang.org>
Sat, 7 Sep 2013 03:10:57 +0000 (20:10 -0700)
committerbors <bors@rust-lang.org>
Sat, 7 Sep 2013 03:10:57 +0000 (20:10 -0700)
Here's a fix for issue #7588, "Overflow handling of from_str methods is broken".

The integer overflow issues are taken care of by checking to see if the multiply-by-radix-and-add-next-digit process is reversible. If it overflowed, then some information is lost and the process is irreversible, in which case, None is returned.

Floats now consistently return Some(Inf) of Some(-Inf) on overflow thanks to a call to NumStrConv::inf() and NumStrConv::neg_inf() respectively when the overflow is detected (which yields a value of None in the case of ints and uints anyway).

This is my first contribution to Rust, and my first time using the language in general, so any and all feedback is appreciated.

src/libstd/num/strconv.rs

index edfabd339af5c8e0987b64b7286a33a0e88d789d..dcda27d8ea923fcb9caf76ba86f696312ccf2d52 100644 (file)
@@ -552,8 +552,18 @@ pub fn from_str_bytes_common<T:NumCast+Zero+One+Eq+Ord+Div<T,T>+
                 // Detect overflow by comparing to last value, except
                 // if we've not seen any non-zero digits.
                 if last_accum != _0 {
-                    if accum_positive && accum <= last_accum { return None; }
-                    if !accum_positive && accum >= last_accum { return None; }
+                    if accum_positive && accum <= last_accum { return NumStrConv::inf(); }
+                    if !accum_positive && accum >= last_accum { return NumStrConv::neg_inf(); }
+
+                    // Detect overflow by reversing the shift-and-add proccess
+                    if accum_positive &&
+                        (last_accum != ((accum - cast(digit as int))/radix_gen.clone())) {
+                        return NumStrConv::inf();
+                    }
+                    if !accum_positive &&
+                        (last_accum != ((accum + cast(digit as int))/radix_gen.clone())) {
+                        return NumStrConv::neg_inf();
+                    }
                 }
                 last_accum = accum.clone();
             }
@@ -597,8 +607,8 @@ pub fn from_str_bytes_common<T:NumCast+Zero+One+Eq+Ord+Div<T,T>+
                     }
 
                     // Detect overflow by comparing to last value
-                    if accum_positive && accum < last_accum { return None; }
-                    if !accum_positive && accum > last_accum { return None; }
+                    if accum_positive && accum < last_accum { return NumStrConv::inf(); }
+                    if !accum_positive && accum > last_accum { return NumStrConv::neg_inf(); }
                     last_accum = accum.clone();
                 }
                 None => match c {
@@ -702,6 +712,23 @@ fn from_str_issue5770() {
                                              ExpNone, false, false);
         assert_eq!(n, None);
     }
+
+    #[test]
+    fn from_str_issue7588() {
+        let u : Option<u8> = from_str_common("1000", 10, false, false, false,
+                                            ExpNone, false, false);
+        assert_eq!(u, None);
+        let s : Option<i16> = from_str_common("80000", 10, false, false, false,
+                                             ExpNone, false, false);
+        assert_eq!(s, None);
+        let f : Option<f32> = from_str_common(
+            "10000000000000000000000000000000000000000", 10, false, false, false,
+            ExpNone, false, false);
+        assert_eq!(f, NumStrConv::inf())
+        let fe : Option<f32> = from_str_common("1e40", 10, false, false, false,
+                                            ExpDec, false, false);
+        assert_eq!(fe, NumStrConv::inf())
+    }
 }
 
 #[cfg(test)]