Skip to content

Commit

Permalink
PyLong_FromSsize_t was incorrect when sizeof(size_t) > sizeof(long);
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
mdickinson committed Apr 15, 2008
1 parent 32dde22 commit 7ab6be2
Show file tree
Hide file tree
Showing 2 changed files with 56 additions and 12 deletions.
3 changes: 3 additions & 0 deletions Misc/NEWS
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
65 changes: 53 additions & 12 deletions Objects/longobject.c
Original file line number Diff line number Diff line change
Expand Up @@ -1099,27 +1099,68 @@ 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. */

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.
Expand Down

0 comments on commit 7ab6be2

Please sign in to comment.