From: Mark Dickinson Date: Mon, 19 Sep 2011 15:38:08 +0000 (+0100) Subject: Issue #12973: Fix int.__pow__ overflow checks that invoked undefined behaviour, there... X-Git-Tag: v2.7.3rc1~446 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=dbbed0494113ab7631777c4996a7971770f2dcc1;p=thirdparty%2FPython%2Fcpython.git Issue #12973: Fix int.__pow__ overflow checks that invoked undefined behaviour, thereby producing incorrect results on Clang. --- diff --git a/Misc/NEWS b/Misc/NEWS index 2b6788313eef..72d7a0957557 100644 --- 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. diff --git a/Objects/intobject.c b/Objects/intobject.c index 7d70bfb6e399..e518e74bbb14 100644 --- a/Objects/intobject.c +++ b/Objects/intobject.c @@ -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);