Skip to content

Commit 49cdf36

Browse files
committed
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.
1 parent 44d4d6d commit 49cdf36

File tree

1 file changed

+24
-5
lines changed

1 file changed

+24
-5
lines changed

Diff for: src/libcore/num/strconv.rs

+24-5
Original file line numberDiff line numberDiff line change
@@ -448,7 +448,7 @@ priv static DIGIT_E_RADIX: uint = ('e' as uint) - ('a' as uint) + 11u;
448448
* - Could accept option to allow ignoring underscores, allowing for numbers
449449
* formated like `FF_AE_FF_FF`.
450450
*/
451-
pub fn from_str_bytes_common<T:NumCast+Zero+One+Ord+Copy+Div<T,T>+
451+
pub fn from_str_bytes_common<T:NumCast+Zero+One+Eq+Ord+Copy+Div<T,T>+
452452
Mul<T,T>+Sub<T,T>+Neg<T>+Add<T,T>+
453453
NumStrConv>(
454454
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>+
531531
accum -= cast(digit as int);
532532
}
533533

534-
// Detect overflow by comparing to last value
535-
if accum_positive && accum < last_accum { return None; }
536-
if !accum_positive && accum > last_accum { return None; }
534+
// Detect overflow by comparing to last value, except
535+
// if we've not seen any non-zero digits.
536+
if last_accum != _0 {
537+
if accum_positive && accum <= last_accum { return None; }
538+
if !accum_positive && accum >= last_accum { return None; }
539+
}
537540
last_accum = accum;
538541
}
539542
None => match c {
@@ -637,11 +640,27 @@ pub fn from_str_bytes_common<T:NumCast+Zero+One+Ord+Copy+Div<T,T>+
637640
* `from_str_bytes_common()`, for details see there.
638641
*/
639642
#[inline(always)]
640-
pub fn from_str_common<T:NumCast+Zero+One+Ord+Copy+Div<T,T>+Mul<T,T>+
643+
pub fn from_str_common<T:NumCast+Zero+One+Eq+Ord+Copy+Div<T,T>+Mul<T,T>+
641644
Sub<T,T>+Neg<T>+Add<T,T>+NumStrConv>(
642645
buf: &str, radix: uint, negative: bool, fractional: bool,
643646
special: bool, exponent: ExponentFormat, empty_zero: bool
644647
) -> Option<T> {
645648
from_str_bytes_common(str::to_bytes(buf), radix, negative,
646649
fractional, special, exponent, empty_zero)
647650
}
651+
652+
#[cfg(test)]
653+
mod test {
654+
use super::*;
655+
use option::*;
656+
657+
#[test]
658+
fn from_str_issue5770() {
659+
// try to parse 0b1_1111_1111 = 511 as a u8. Caused problems
660+
// since 255*2+1 == 255 (mod 256) so the overflow wasn't
661+
// detected.
662+
let n : Option<u8> = from_str_common("111111111", 2, false, false, false,
663+
ExpNone, false);
664+
assert_eq!(n, None);
665+
}
666+
}

0 commit comments

Comments
 (0)