]> granicus.if.org Git - python/commitdiff
PyLong_FromSsize_t was incorrect when sizeof(size_t) > sizeof(long);
authorMark Dickinson <dickinsm@gmail.com>
Tue, 15 Apr 2008 21:42:42 +0000 (21:42 +0000)
committerMark Dickinson <dickinsm@gmail.com>
Tue, 15 Apr 2008 21:42:42 +0000 (21:42 +0000)
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
Objects/longobject.c

index 58524ee830ba1596bf3f26b4f94edd93ee209082..7a8744f421117fb4d6bc879c7159d93141e06007 100644 (file)
--- 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.
index 1d4b502f847f8138e4198a3431beb4184e36f9a9..44b040cf9e3521b69851fe6ba8263bd6d183e833 100644 (file)
@@ -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.