Commit dbbed049 authored by Mark Dickinson's avatar Mark Dickinson

Issue #12973: Fix int.__pow__ overflow checks that invoked undefined...

Issue #12973: Fix int.__pow__ overflow checks that invoked undefined behaviour, thereby producing incorrect results on Clang.
parent d256ca12
...@@ -9,6 +9,11 @@ What's New in Python 2.7.3? ...@@ -9,6 +9,11 @@ What's New in Python 2.7.3?
Core and Builtins 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 - Issue #12266: Fix str.capitalize() to correctly uppercase/lowercase
titlecased and cased non-letter characters. titlecased and cased non-letter characters.
......
...@@ -751,7 +751,13 @@ int_pow(PyIntObject *v, PyIntObject *w, PyIntObject *z) ...@@ -751,7 +751,13 @@ int_pow(PyIntObject *v, PyIntObject *w, PyIntObject *z)
while (iw > 0) { while (iw > 0) {
prev = ix; /* Save value for overflow check */ prev = ix; /* Save value for overflow check */
if (iw & 1) { 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) if (temp == 0)
break; /* Avoid ix / 0 */ break; /* Avoid ix / 0 */
if (ix / temp != prev) { if (ix / temp != prev) {
...@@ -764,7 +770,7 @@ int_pow(PyIntObject *v, PyIntObject *w, PyIntObject *z) ...@@ -764,7 +770,7 @@ int_pow(PyIntObject *v, PyIntObject *w, PyIntObject *z)
iw >>= 1; /* Shift exponent down by 1 bit */ iw >>= 1; /* Shift exponent down by 1 bit */
if (iw==0) break; if (iw==0) break;
prev = temp; 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) { if (prev != 0 && temp / prev != prev) {
return PyLong_Type.tp_as_number->nb_power( return PyLong_Type.tp_as_number->nb_power(
(PyObject *)v, (PyObject *)w, (PyObject *)z); (PyObject *)v, (PyObject *)w, (PyObject *)z);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment