Fix for possible signed overflow: the behaviour of -LONG_MIN is
undefined in ANSI C.
This commit is contained in:
parent
8c65b1ed78
commit
27a632510e
|
@ -99,20 +99,27 @@ PyObject *
|
||||||
PyLong_FromLong(long ival)
|
PyLong_FromLong(long ival)
|
||||||
{
|
{
|
||||||
PyLongObject *v;
|
PyLongObject *v;
|
||||||
|
unsigned long abs_ival;
|
||||||
unsigned long t; /* unsigned so >> doesn't propagate sign bit */
|
unsigned long t; /* unsigned so >> doesn't propagate sign bit */
|
||||||
int ndigits = 0;
|
int ndigits = 0;
|
||||||
int negative = 0;
|
int negative = 0;
|
||||||
|
|
||||||
if (ival < 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;
|
negative = 1;
|
||||||
}
|
}
|
||||||
|
else {
|
||||||
|
abs_ival = (unsigned long)ival;
|
||||||
|
}
|
||||||
|
|
||||||
/* Count the number of Python digits.
|
/* Count the number of Python digits.
|
||||||
We used to pick 5 ("big enough for anything"), but that's a
|
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
|
waste of time and space given that 5*15 = 75 bits are rarely
|
||||||
needed. */
|
needed. */
|
||||||
t = (unsigned long)ival;
|
t = abs_ival;
|
||||||
while (t) {
|
while (t) {
|
||||||
++ndigits;
|
++ndigits;
|
||||||
t >>= PyLong_SHIFT;
|
t >>= PyLong_SHIFT;
|
||||||
|
@ -121,7 +128,7 @@ PyLong_FromLong(long ival)
|
||||||
if (v != NULL) {
|
if (v != NULL) {
|
||||||
digit *p = v->ob_digit;
|
digit *p = v->ob_digit;
|
||||||
v->ob_size = negative ? -ndigits : ndigits;
|
v->ob_size = negative ? -ndigits : ndigits;
|
||||||
t = (unsigned long)ival;
|
t = abs_ival;
|
||||||
while (t) {
|
while (t) {
|
||||||
*p++ = (digit)(t & PyLong_MASK);
|
*p++ = (digit)(t & PyLong_MASK);
|
||||||
t >>= PyLong_SHIFT;
|
t >>= PyLong_SHIFT;
|
||||||
|
@ -830,20 +837,26 @@ PyObject *
|
||||||
PyLong_FromLongLong(PY_LONG_LONG ival)
|
PyLong_FromLongLong(PY_LONG_LONG ival)
|
||||||
{
|
{
|
||||||
PyLongObject *v;
|
PyLongObject *v;
|
||||||
|
unsigned PY_LONG_LONG abs_ival;
|
||||||
unsigned PY_LONG_LONG t; /* unsigned so >> doesn't propagate sign bit */
|
unsigned PY_LONG_LONG t; /* unsigned so >> doesn't propagate sign bit */
|
||||||
int ndigits = 0;
|
int ndigits = 0;
|
||||||
int negative = 0;
|
int negative = 0;
|
||||||
|
|
||||||
if (ival < 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;
|
negative = 1;
|
||||||
}
|
}
|
||||||
|
else {
|
||||||
|
abs_ival = (unsigned PY_LONG_LONG)ival;
|
||||||
|
}
|
||||||
|
|
||||||
/* Count the number of Python digits.
|
/* Count the number of Python digits.
|
||||||
We used to pick 5 ("big enough for anything"), but that's a
|
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
|
waste of time and space given that 5*15 = 75 bits are rarely
|
||||||
needed. */
|
needed. */
|
||||||
t = (unsigned PY_LONG_LONG)ival;
|
t = abs_ival;
|
||||||
while (t) {
|
while (t) {
|
||||||
++ndigits;
|
++ndigits;
|
||||||
t >>= PyLong_SHIFT;
|
t >>= PyLong_SHIFT;
|
||||||
|
@ -852,7 +865,7 @@ PyLong_FromLongLong(PY_LONG_LONG ival)
|
||||||
if (v != NULL) {
|
if (v != NULL) {
|
||||||
digit *p = v->ob_digit;
|
digit *p = v->ob_digit;
|
||||||
Py_SIZE(v) = negative ? -ndigits : ndigits;
|
Py_SIZE(v) = negative ? -ndigits : ndigits;
|
||||||
t = (unsigned PY_LONG_LONG)ival;
|
t = abs_ival;
|
||||||
while (t) {
|
while (t) {
|
||||||
*p++ = (digit)(t & PyLong_MASK);
|
*p++ = (digit)(t & PyLong_MASK);
|
||||||
t >>= PyLong_SHIFT;
|
t >>= PyLong_SHIFT;
|
||||||
|
|
Loading…
Reference in New Issue