summaryrefslogtreecommitdiffstats
path: root/Objects/longobject.c
diff options
context:
space:
mode:
Diffstat (limited to 'Objects/longobject.c')
-rw-r--r--Objects/longobject.c25
1 files changed, 19 insertions, 6 deletions
diff --git a/Objects/longobject.c b/Objects/longobject.c
index d88a13e..fa0142f 100644
--- a/Objects/longobject.c
+++ b/Objects/longobject.c
@@ -160,6 +160,7 @@ PyObject *
PyLong_FromLong(long ival)
{
PyLongObject *v;
+ unsigned long abs_ival;
unsigned long t; /* unsigned so >> doesn't propagate sign bit */
int ndigits = 0;
int sign = 1;
@@ -167,9 +168,15 @@ PyLong_FromLong(long ival)
CHECK_SMALL_INT(ival);
if (ival < 0) {
- ival = -ival;
+ /* if LONG_MIN == -LONG_MAX-1 (true on most platforms) then
+ ANSI C says that the result of -ival is undefined when ival
+ == LONG_MIN. Hence the following workaround. */
+ abs_ival = (unsigned long)(-1-ival) + 1;
sign = -1;
}
+ else {
+ abs_ival = (unsigned long)ival;
+ }
/* Fast path for single-digits ints */
if (!(ival>>PyLong_SHIFT)) {
@@ -193,7 +200,7 @@ PyLong_FromLong(long ival)
}
/* Larger numbers: loop to determine number of digits */
- t = (unsigned long)ival;
+ t = abs_ival;
while (t) {
++ndigits;
t >>= PyLong_SHIFT;
@@ -202,7 +209,7 @@ PyLong_FromLong(long ival)
if (v != NULL) {
digit *p = v->ob_digit;
Py_SIZE(v) = ndigits*sign;
- t = (unsigned long)ival;
+ t = abs_ival;
while (t) {
*p++ = (digit)(t & PyLong_MASK);
t >>= PyLong_SHIFT;
@@ -1033,21 +1040,27 @@ PyObject *
PyLong_FromLongLong(PY_LONG_LONG ival)
{
PyLongObject *v;
+ unsigned PY_LONG_LONG abs_ival;
unsigned PY_LONG_LONG t; /* unsigned so >> doesn't propagate sign bit */
int ndigits = 0;
int negative = 0;
CHECK_SMALL_INT(ival);
if (ival < 0) {
- ival = -ival;
+ /* avoid signed overflow on negation; see comments
+ in PyLong_FromLong above. */
+ abs_ival = (unsigned PY_LONG_LONG)(-1-ival) + 1;
negative = 1;
}
+ else {
+ abs_ival = (unsigned PY_LONG_LONG)ival;
+ }
/* Count the number of Python digits.
We used to pick 5 ("big enough for anything"), but that's a
waste of time and space given that 5*15 = 75 bits are rarely
needed. */
- t = (unsigned PY_LONG_LONG)ival;
+ t = abs_ival;
while (t) {
++ndigits;
t >>= PyLong_SHIFT;
@@ -1056,7 +1069,7 @@ PyLong_FromLongLong(PY_LONG_LONG ival)
if (v != NULL) {
digit *p = v->ob_digit;
Py_SIZE(v) = negative ? -ndigits : ndigits;
- t = (unsigned PY_LONG_LONG)ival;
+ t = abs_ival;
while (t) {
*p++ = (digit)(t & PyLong_MASK);
t >>= PyLong_SHIFT;