]> granicus.if.org Git - python/commitdiff
Issue #12973: Fix int.__pow__ overflow checks that invoked undefined behaviour, there...
authorMark Dickinson <mdickinson@enthought.com>
Mon, 19 Sep 2011 15:38:08 +0000 (16:38 +0100)
committerMark Dickinson <mdickinson@enthought.com>
Mon, 19 Sep 2011 15:38:08 +0000 (16:38 +0100)
Misc/NEWS
Objects/intobject.c

index 2b6788313eef230dd534ecbaecac8291dae303e5..72d7a0957557f17f614255d37e3f5e5f849404a0 100644 (file)
--- a/Misc/NEWS
+++ b/Misc/NEWS
@@ -9,6 +9,11 @@ What's New in Python 2.7.3?
 Core and Builtins
 -----------------
 
+- Issue #12973: Fix overflow checks that invoked undefined behaviour in
+  int.__pow__.  These overflow checks were causing int.__pow__ to produce
+  incorrect results with recent versions of Clang, as a result of the
+  compiler optimizing the check away.
+
 - Issue #12266: Fix str.capitalize() to correctly uppercase/lowercase
   titlecased and cased non-letter characters.
 
index 7d70bfb6e399f1ef0ebf48306ae99879ece0944b..e518e74bbb14e6f6bbe92f6cdcefbf9e71f73648 100644 (file)
@@ -751,7 +751,13 @@ int_pow(PyIntObject *v, PyIntObject *w, PyIntObject *z)
     while (iw > 0) {
         prev = ix;              /* Save value for overflow check */
         if (iw & 1) {
-            ix = ix*temp;
+            /*
+             * The (unsigned long) cast below ensures that the multiplication
+             * is interpreted as an unsigned operation rather than a signed one
+             * (C99 6.3.1.8p1), thus avoiding the perils of undefined behaviour
+             * from signed arithmetic overflow (C99 6.5p5).  See issue #12973.
+             */
+            ix = (unsigned long)ix * temp;
             if (temp == 0)
                 break; /* Avoid ix / 0 */
             if (ix / temp != prev) {
@@ -764,7 +770,7 @@ int_pow(PyIntObject *v, PyIntObject *w, PyIntObject *z)
         iw >>= 1;               /* Shift exponent down by 1 bit */
         if (iw==0) break;
         prev = temp;
-        temp *= temp;           /* Square the value of temp */
+        temp = (unsigned long)temp * temp;  /* Square the value of temp */
         if (prev != 0 && temp / prev != prev) {
             return PyLong_Type.tp_as_number->nb_power(
                 (PyObject *)v, (PyObject *)w, (PyObject *)z);