[Python-checkins] r62355 - python/trunk/Objects/longobject.c
mark.dickinson
python-checkins at python.org
Tue Apr 15 22:51:18 CEST 2008
Author: mark.dickinson
Date: Tue Apr 15 22:51:18 2008
New Revision: 62355
Log:
Fix for possible signed overflow: the behaviour of -LONG_MIN is
undefined in ANSI C.
Modified:
python/trunk/Objects/longobject.c
Modified: python/trunk/Objects/longobject.c
==============================================================================
--- python/trunk/Objects/longobject.c (original)
+++ python/trunk/Objects/longobject.c Tue Apr 15 22:51:18 2008
@@ -99,20 +99,27 @@
PyLong_FromLong(long ival)
{
PyLongObject *v;
+ unsigned long abs_ival;
unsigned long t; /* unsigned so >> doesn't propagate sign bit */
int ndigits = 0;
int negative = 0;
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;
negative = 1;
}
+ else {
+ abs_ival = (unsigned 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 long)ival;
+ t = abs_ival;
while (t) {
++ndigits;
t >>= PyLong_SHIFT;
@@ -121,7 +128,7 @@
if (v != NULL) {
digit *p = v->ob_digit;
v->ob_size = negative ? -ndigits : ndigits;
- t = (unsigned long)ival;
+ t = abs_ival;
while (t) {
*p++ = (digit)(t & PyLong_MASK);
t >>= PyLong_SHIFT;
@@ -830,20 +837,26 @@
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;
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;
@@ -852,7 +865,7 @@
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;
More information about the Python-checkins
mailing list