From 7ab6be216af6fccae655bd5402ae0ad22447f37a Mon Sep 17 00:00:00 2001 From: Mark Dickinson Date: Tue, 15 Apr 2008 21:42:42 +0000 Subject: PyLong_FromSsize_t was incorrect when sizeof(size_t) > sizeof(long); rewrite it so that it doesn't care about relative sizes of size_t, long and long long. The rewrite is modeled on PyLong_FromLong, instead of using PyLong_FromByteArray; this makes the algorithm simpler and more direct, and possibly also slightly faster. --- Misc/NEWS | 3 +++ Objects/longobject.c | 65 ++++++++++++++++++++++++++++++++++++++++++---------- 2 files changed, 56 insertions(+), 12 deletions(-) diff --git a/Misc/NEWS b/Misc/NEWS index 58524ee..7a8744f 100644 --- a/Misc/NEWS +++ b/Misc/NEWS @@ -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. -- cgit v0.12