1
Fork 0

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.
This commit is contained in:
Huon Wilson 2013-04-08 01:26:51 +10:00
parent 44d4d6de76
commit 49cdf36d2b

View file

@ -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 * - Could accept option to allow ignoring underscores, allowing for numbers
* formated like `FF_AE_FF_FF`. * 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>+ Mul<T,T>+Sub<T,T>+Neg<T>+Add<T,T>+
NumStrConv>( NumStrConv>(
buf: &[u8], radix: uint, negative: bool, fractional: bool, 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); accum -= cast(digit as int);
} }
// Detect overflow by comparing to last value // Detect overflow by comparing to last value, except
if accum_positive && accum < last_accum { return None; } // if we've not seen any non-zero digits.
if !accum_positive && accum > last_accum { return None; } if last_accum != _0 {
if accum_positive && accum <= last_accum { return None; }
if !accum_positive && accum >= last_accum { return None; }
}
last_accum = accum; last_accum = accum;
} }
None => match c { 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. * `from_str_bytes_common()`, for details see there.
*/ */
#[inline(always)] #[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>( Sub<T,T>+Neg<T>+Add<T,T>+NumStrConv>(
buf: &str, radix: uint, negative: bool, fractional: bool, buf: &str, radix: uint, negative: bool, fractional: bool,
special: bool, exponent: ExponentFormat, empty_zero: 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, from_str_bytes_common(str::to_bytes(buf), radix, negative,
fractional, special, exponent, empty_zero) 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);
}
}