about summary refs log tree commit diff
diff options
context:
space:
mode:
authorgifnksm <makoto.nksm+github@gmail.com>2013-04-29 11:53:01 +0900
committergifnksm <makoto.nksm+github@gmail.com>2013-04-29 13:49:27 +0900
commitffa31d235badfb5544ddb2de151ccfc66c8a20e6 (patch)
tree977283606f18bc2c776add3622314daa53edb67b
parente4ca2da42072fccd16aefdc4f2090b0489e8293c (diff)
downloadrust-ffa31d235badfb5544ddb2de151ccfc66c8a20e6.tar.gz
rust-ffa31d235badfb5544ddb2de151ccfc66c8a20e6.zip
libstd: modify wrong shift width.
borrow = *elem << (uint::bits - n_bits);

The code above contains a bug that the value of the right operand of the shift operator exceeds the size of the left operand,
because sizeof(*elem) == 32, and 0 <= n_bits < 32 in 64bit architecture.

If `--opt-level` option is not given to rustc, the code above runs as if the right operand is `(uint::bits - n_bits) % 32`,
but if --opt-level is given, `borrow` is always zero.

I wonder why this bug is not catched in the libstd's testsuite (I try the `rustc --test --opt-level=2 bigint.rs` before fixing the bug,
but the unittest passes normally.)
-rw-r--r--src/libstd/num/bigint.rs3
1 files changed, 2 insertions, 1 deletions
diff --git a/src/libstd/num/bigint.rs b/src/libstd/num/bigint.rs
index 74e5b00d896..526272883b7 100644
--- a/src/libstd/num/bigint.rs
+++ b/src/libstd/num/bigint.rs
@@ -623,7 +623,7 @@ impl BigUint {
         let mut shifted = ~[];
         for self.data.each_reverse |elem| {
             shifted = ~[(*elem >> n_bits) | borrow] + shifted;
-            borrow = *elem << (uint::bits - n_bits);
+            borrow = *elem << (BigDigit::bits - n_bits);
         }
         return BigUint::new(shifted);
     }
@@ -1213,6 +1213,7 @@ mod biguint_tests {
         check(~[1 << 2], 2, ~[1]);
         check(~[1, 2], 3, ~[1 << (BigDigit::bits - 2)]);
         check(~[1, 1, 2], 3 + BigDigit::bits, ~[1 << (BigDigit::bits - 2)]);
+        check(~[0, 1], 1, ~[0x80000000]);
         test_shr_bits();
 
         #[cfg(target_arch = "x86_64")]