diff options
-rw-r--r-- | Misc/NEWS | 3 | ||||
-rw-r--r-- | Objects/longobject.c | 65 |
2 files changed, 56 insertions, 12 deletions
@@ -12,6 +12,9 @@ What's New in Python 3.0a5? Core and Builtins ----------------- +- Fix misbehaviour of PyLong_FromSsize_t on systems where sizeof(size_t) > + sizeof(long). + - Issue #2221: Corrected a SystemError "error return without exception set", when the code executed by exec() raises an exception, and sys.stdout.flush() also raises an error. diff --git a/Objects/longobject.c b/Objects/longobject.c index 1d4b502..44b040c 100644 --- a/Objects/longobject.c +++ b/Objects/longobject.c @@ -1099,13 +1099,39 @@ PyLong_FromUnsignedLongLong(unsigned PY_LONG_LONG ival) PyObject * PyLong_FromSsize_t(Py_ssize_t ival) { - Py_ssize_t bytes = ival; - int one = 1; - if (ival < PyLong_BASE) - return PyLong_FromLong(ival); - return _PyLong_FromByteArray( - (unsigned char *)&bytes, - SIZEOF_SIZE_T, IS_LITTLE_ENDIAN, 1); + PyLongObject *v; + size_t abs_ival; + size_t t; /* unsigned so >> doesn't propagate sign bit */ + int ndigits = 0; + int negative = 0; + + CHECK_SMALL_INT(ival); + if (ival < 0) { + /* avoid signed overflow when ival = SIZE_T_MIN */ + abs_ival = (size_t)(-1-ival)+1; + negative = 1; + } + else { + abs_ival = (size_t)ival; + } + + /* Count the number of Python digits. */ + t = abs_ival; + while (t) { + ++ndigits; + t >>= PyLong_SHIFT; + } + v = _PyLong_New(ndigits); + if (v != NULL) { + digit *p = v->ob_digit; + Py_SIZE(v) = negative ? -ndigits : ndigits; + t = abs_ival; + while (t) { + *p++ = (digit)(t & PyLong_MASK); + t >>= PyLong_SHIFT; + } + } + return (PyObject *)v; } /* Create a new long int object from a C size_t. */ @@ -1113,13 +1139,28 @@ PyLong_FromSsize_t(Py_ssize_t ival) PyObject * PyLong_FromSize_t(size_t ival) { - size_t bytes = ival; - int one = 1; + PyLongObject *v; + size_t t; + int ndigits = 0; + if (ival < PyLong_BASE) return PyLong_FromLong(ival); - return _PyLong_FromByteArray( - (unsigned char *)&bytes, - SIZEOF_SIZE_T, IS_LITTLE_ENDIAN, 0); + /* Count the number of Python digits. */ + t = ival; + while (t) { + ++ndigits; + t >>= PyLong_SHIFT; + } + v = _PyLong_New(ndigits); + if (v != NULL) { + digit *p = v->ob_digit; + Py_SIZE(v) = ndigits; + while (ival) { + *p++ = (digit)(ival & PyLong_MASK); + ival >>= PyLong_SHIFT; + } + } + return (PyObject *)v; } /* Get a C PY_LONG_LONG int from a long int object. |