about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2015-09-14 17:10:09 +0000
committerbors <bors@rust-lang.org>2015-09-14 17:10:09 +0000
commit9da7706dd64bbf055e3f32fe12286a521d8ac7ac (patch)
tree5d2641ab3f3e67e62a66e84638ff982f6f097ce2
parent2d4ae52cbdca96d4dd6d5a009e4a5ef87a279df0 (diff)
parenta593a211fe71e82b3f87dd16fb25831fb8a00442 (diff)
downloadrust-9da7706dd64bbf055e3f32fe12286a521d8ac7ac.tar.gz
rust-9da7706dd64bbf055e3f32fe12286a521d8ac7ac.zip
Auto merge of #28248 - PeterReid:master, r=alexcrichton
Overflows in integer pow() computations would be missed if they
preceded a 0 bit of the exponent being processed. This made
calls such as 2i32.pow(1024) not trigger an overflow.

Fixes #28012
-rw-r--r--src/libcore/num/mod.rs26
-rw-r--r--src/test/run-fail/overflowing-pow.rs16
2 files changed, 27 insertions, 15 deletions
diff --git a/src/libcore/num/mod.rs b/src/libcore/num/mod.rs
index 05c7e8b8de4..127f8d3b5a2 100644
--- a/src/libcore/num/mod.rs
+++ b/src/libcore/num/mod.rs
@@ -537,25 +537,21 @@ macro_rules! int_impl {
             let mut base = self;
             let mut acc = Self::one();
 
-            let mut prev_base = self;
-            let mut base_oflo = false;
-            while exp > 0 {
+            while exp > 1 {
                 if (exp & 1) == 1 {
-                    if base_oflo {
-                        // ensure overflow occurs in the same manner it
-                        // would have otherwise (i.e. signal any exception
-                        // it would have otherwise).
-                        acc = acc * (prev_base * prev_base);
-                    } else {
-                        acc = acc * base;
-                    }
+                    acc = acc * base;
                 }
-                prev_base = base;
-                let (new_base, new_base_oflo) = base.overflowing_mul(base);
-                base = new_base;
-                base_oflo = new_base_oflo;
                 exp /= 2;
+                base = base * base;
+            }
+
+            // Deal with the final bit of the exponent separately, since
+            // squaring the base afterwards is not necessary and may cause a
+            // needless overflow.
+            if exp == 1 {
+                acc = acc * base;
             }
+
             acc
         }
 
diff --git a/src/test/run-fail/overflowing-pow.rs b/src/test/run-fail/overflowing-pow.rs
new file mode 100644
index 00000000000..15335b8dfb1
--- /dev/null
+++ b/src/test/run-fail/overflowing-pow.rs
@@ -0,0 +1,16 @@
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// error-pattern:thread '<main>' panicked at 'arithmetic operation overflowed'
+// compile-flags: -C debug-assertions
+
+fn main() {
+    let _x = 2i32.pow(1024);
+}