diff options
author | Guido van Rossum <guido@python.org> | 1998-05-26 14:33:37 (GMT) |
---|---|---|
committer | Guido van Rossum <guido@python.org> | 1998-05-26 14:33:37 (GMT) |
commit | f753181272d9f69ec9cea4330cfd0af1fcabc935 (patch) | |
tree | 1284fe12ed5a9a6f5b5e477b8b1df252bf9b41cf | |
parent | 2028dd04236c9b960de5e2febd49abff039e665b (diff) | |
download | cpython-f753181272d9f69ec9cea4330cfd0af1fcabc935.zip cpython-f753181272d9f69ec9cea4330cfd0af1fcabc935.tar.gz cpython-f753181272d9f69ec9cea4330cfd0af1fcabc935.tar.bz2 |
Subject: Buglet in PyLong_AsLong
From: "Tim Peters" <tim_one@email.msn.com>
To: "Guido van Rossum" <guido@CNRI.Reston.VA.US>
Date: Sat, 23 May 1998 21:45:53 -0400
Guido, the overflow checking in PyLong_AsLong is off a little:
1) If the C in use sign-extends right shifts on signed longs, there's a
spurious overflow error when converting the most-negative int:
Python 1.5.1 (#0, Apr 13 1998, 20:22:04) [MSC 32 bit (Intel)] on win32
Copyright 1991-1995 Stichting Mathematisch Centrum, Amsterdam
>>> x = -1L << 31
>>> x
-2147483648L
>>> int(x)
Traceback (innermost last):
File "<stdin>", line 1, in ?
OverflowError: long int too long to convert
>>>
2) If C does not sign-extend, some genuine overflows won't be caught.
The attached should repair both, and, because I installed a new disk and a C
compiler today, it's even been compiled this time <wink>.
Python 1.5.1 (#0, May 23 1998, 20:24:58) [MSC 32 bit (Intel)] on win32
Copyright 1991-1995 Stichting Mathematisch Centrum, Amsterdam
>>> x = -1L << 31
>>> x
-2147483648L
>>> int(x)
-2147483648
>>> int(-x)
Traceback (innermost last):
File "<stdin>", line 1, in ?
OverflowError: long int too long to convert
>>> int(-x-1)
2147483647
>>> int(x-1)
Traceback (innermost last):
File "<stdin>", line 1, in ?
OverflowError: long int too long to convert
>>>
end-casing-ly y'rs - tim
-rw-r--r-- | Objects/longobject.c | 28 |
1 files changed, 19 insertions, 9 deletions
diff --git a/Objects/longobject.c b/Objects/longobject.c index becf1bc..9657c08 100644 --- a/Objects/longobject.c +++ b/Objects/longobject.c @@ -175,10 +175,11 @@ long PyLong_AsLong(vv) PyObject *vv; { + /* This version by Tim Peters */ register PyLongObject *v; - long x, prev; + unsigned long x, prev; int i, sign; - + if (vv == NULL || !PyLong_Check(vv)) { PyErr_BadInternalCall(); return -1; @@ -194,13 +195,22 @@ PyLong_AsLong(vv) while (--i >= 0) { prev = x; x = (x << SHIFT) + v->ob_digit[i]; - if ((x >> SHIFT) != prev) { - PyErr_SetString(PyExc_OverflowError, - "long int too long to convert"); - return -1; - } - } - return x * sign; + if ((x >> SHIFT) != prev) + goto overflow; + } + /* Haven't lost any bits, but if the sign bit is set we're in + * trouble *unless* this is the min negative number. So, + * trouble iff sign bit set && (positive || some bit set other + * than the sign bit). + */ + if ((long)x < 0 && (sign > 0 || (x << 1) != 0)) + goto overflow; + return (long)x * sign; + + overflow: + PyErr_SetString(PyExc_OverflowError, + "long int too long to convert"); + return -1; } /* Get a C long int from a long int object. |