diff options
| author | Huon Wilson <dbau.pp+github@gmail.com> | 2013-04-08 01:26:51 +1000 |
|---|---|---|
| committer | Huon Wilson <dbau.pp+github@gmail.com> | 2013-04-08 16:35:39 +1000 |
| commit | 49cdf36d2b993e08833bfdda2563b0c22ee42de7 (patch) | |
| tree | dbb074de8dcc1ce5ab5e3b45879290f878a3aaac /src | |
| parent | 44d4d6de762f3f9aae1fedcf454c66b79b3ad58d (diff) | |
| download | rust-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.rs | 29 |
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); + } +} |
