about summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
authorHuon Wilson <dbau.pp+github@gmail.com>2013-04-08 01:26:51 +1000
committerHuon Wilson <dbau.pp+github@gmail.com>2013-04-08 16:35:39 +1000
commit49cdf36d2b993e08833bfdda2563b0c22ee42de7 (patch)
treedbb074de8dcc1ce5ab5e3b45879290f878a3aaac /src
parent44d4d6de762f3f9aae1fedcf454c66b79b3ad58d (diff)
downloadrust-49cdf36d2b993e08833bfdda2563b0c22ee42de7.tar.gz
rust-49cdf36d2b993e08833bfdda2563b0c22ee42de7.zip
libcore: from_str_common: correctly signal failure on repeating base 2^n numbers.
A number like 0b1_1111_1111 == 511 would be parsed to Some(255u8) rather than None
by from_str_common, since 255 * 2 + 1 == 255 (mod 256) so the overflow wasn't detected.

Only applied to conversions where the radix was a power of 2, and where all digits
repeated.

Closes #5770.
Diffstat (limited to 'src')
-rw-r--r--src/libcore/num/strconv.rs29
1 files changed, 24 insertions, 5 deletions
diff --git a/src/libcore/num/strconv.rs b/src/libcore/num/strconv.rs
index 5299203eb42..687b6344b39 100644
--- a/src/libcore/num/strconv.rs
+++ b/src/libcore/num/strconv.rs
@@ -448,7 +448,7 @@ priv static DIGIT_E_RADIX: uint = ('e' as uint) - ('a' as uint) + 11u;
  * - Could accept option to allow ignoring underscores, allowing for numbers
  *   formated like `FF_AE_FF_FF`.
  */
-pub fn from_str_bytes_common<T:NumCast+Zero+One+Ord+Copy+Div<T,T>+
+pub fn from_str_bytes_common<T:NumCast+Zero+One+Eq+Ord+Copy+Div<T,T>+
                                     Mul<T,T>+Sub<T,T>+Neg<T>+Add<T,T>+
                                     NumStrConv>(
         buf: &[u8], radix: uint, negative: bool, fractional: bool,
@@ -531,9 +531,12 @@ pub fn from_str_bytes_common<T:NumCast+Zero+One+Ord+Copy+Div<T,T>+
                     accum -= cast(digit as int);
                 }
 
-                // Detect overflow by comparing to last value
-                if accum_positive && accum < last_accum { return None; }
-                if !accum_positive && accum > last_accum { return None; }
+                // 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; }
+                }
                 last_accum = accum;
             }
             None => match c {
@@ -637,7 +640,7 @@ pub fn from_str_bytes_common<T:NumCast+Zero+One+Ord+Copy+Div<T,T>+
  * `from_str_bytes_common()`, for details see there.
  */
 #[inline(always)]
-pub fn from_str_common<T:NumCast+Zero+One+Ord+Copy+Div<T,T>+Mul<T,T>+
+pub fn from_str_common<T:NumCast+Zero+One+Eq+Ord+Copy+Div<T,T>+Mul<T,T>+
                               Sub<T,T>+Neg<T>+Add<T,T>+NumStrConv>(
         buf: &str, radix: uint, negative: bool, fractional: bool,
         special: bool, exponent: ExponentFormat, empty_zero: bool
@@ -645,3 +648,19 @@ pub fn from_str_common<T:NumCast+Zero+One+Ord+Copy+Div<T,T>+Mul<T,T>+
     from_str_bytes_common(str::to_bytes(buf), radix, negative,
                             fractional, special, exponent, empty_zero)
 }
+
+#[cfg(test)]
+mod test {
+    use super::*;
+    use option::*;
+
+    #[test]
+    fn from_str_issue5770() {
+        // try to parse 0b1_1111_1111 = 511 as a u8. Caused problems
+        // since 255*2+1 == 255 (mod 256) so the overflow wasn't
+        // detected.
+        let n : Option<u8> = from_str_common("111111111", 2, false, false, false,
+                                             ExpNone, false);
+        assert_eq!(n, None);
+    }
+}