From 49cdf36d2b993e08833bfdda2563b0c22ee42de7 Mon Sep 17 00:00:00 2001 From: Huon Wilson Date: Mon, 8 Apr 2013 01:26:51 +1000 Subject: [PATCH] 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. --- src/libcore/num/strconv.rs | 29 ++++++++++++++++++++++++----- 1 file 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+ +pub fn from_str_bytes_common+ Mul+Sub+Neg+Add+ NumStrConv>( buf: &[u8], radix: uint, negative: bool, fractional: bool, @@ -531,9 +531,12 @@ pub fn from_str_bytes_common+ 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+ * `from_str_bytes_common()`, for details see there. */ #[inline(always)] -pub fn from_str_common+Mul+ +pub fn from_str_common+Mul+ Sub+Neg+Add+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+Mul+ 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 = from_str_common("111111111", 2, false, false, false, + ExpNone, false); + assert_eq!(n, None); + } +}