diff -r e9af9b1ca67e Modules/_randommodule.c --- a/Modules/_randommodule.c Sat Nov 17 19:18:10 2012 +0000 +++ b/Modules/_randommodule.c Sun Nov 18 11:38:59 2012 +0200 @@ -69,6 +69,10 @@ #include "Python.h" #include /* for seeding to current time */ +#ifndef PY_UINT32_T +# error "Failed to find an exact-width 32-bit integer type" +#endif + /* Period parameters -- These are all magic. Don't change. */ #define N 624 #define M 397 @@ -167,8 +171,9 @@ /* initialize by an array with array-length */ /* init_key is the array for initializing keys */ /* key_length is its length */ + static PyObject * -init_by_array(RandomObject *self, unsigned long init_key[], unsigned long key_length) +init_by_array(RandomObject *self, PY_UINT32_T init_key[], size_t key_length) { unsigned int i, j, k; /* was signed in the original code. RDH 12/16/2002 */ unsigned long *mt; @@ -207,15 +212,9 @@ random_seed(RandomObject *self, PyObject *args) { PyObject *result = NULL; /* guilty until proved innocent */ - PyObject *masklower = NULL; - PyObject *thirtytwo = NULL; PyObject *n = NULL; - unsigned long *new_key, *key = NULL; - unsigned long keymax; /* # of allocated slots in key */ - unsigned long keyused; /* # of used slots in key */ - int err; - PyObject *arg = NULL; + size_t bits; if (!PyArg_UnpackTuple(args, "seed", 0, 1, &arg)) return NULL; @@ -243,71 +242,37 @@ if (n == NULL) goto Done; - /* Now split n into 32-bit chunks, from the right. Each piece is - * stored into key, which has a capacity of keymax chunks, of which - * keyused are filled. Alas, the repeated shifting makes this a - * quadratic-time algorithm; we'd really like to use - * _PyLong_AsByteArray here, but then we'd have to break into the - * long representation to figure out how big an array was needed - * in advance. - */ - keymax = 8; /* arbitrary; grows later if needed */ - keyused = 0; - key = (unsigned long *)PyMem_Malloc(keymax * sizeof(*key)); - if (key == NULL) + /* Now split n into 32-bit chunks, from the right. */ + bits = _PyLong_NumBits(n); + if (bits == (size_t)-1 && PyErr_Occurred()) goto Done; - - masklower = PyLong_FromUnsignedLong(0xffffffffU); - if (masklower == NULL) - goto Done; - thirtytwo = PyLong_FromLong(32L); - if (thirtytwo == NULL) - goto Done; - while ((err=PyObject_IsTrue(n))) { - PyObject *newn; - PyObject *pychunk; - unsigned long chunk; - - if (err == -1) - goto Done; - pychunk = PyNumber_And(n, masklower); - if (pychunk == NULL) - goto Done; - chunk = PyLong_AsUnsignedLong(pychunk); - Py_DECREF(pychunk); - if (chunk == (unsigned long)-1 && PyErr_Occurred()) - goto Done; - newn = PyNumber_Rshift(n, thirtytwo); - if (newn == NULL) - goto Done; - Py_DECREF(n); - n = newn; - if (keyused >= keymax) { - unsigned long bigger = keymax << 1; - if ((bigger >> 1) != keymax || - bigger > PY_SSIZE_T_MAX / sizeof(*key)) { - PyErr_NoMemory(); - goto Done; + if (bits) { + size_t keysize = (bits - 1) / 32 + 1; + PY_UINT32_T *key = (PY_UINT32_T *)PyMem_Malloc(keysize * + sizeof(PY_UINT32_T)); + if (_PyLong_AsByteArray((PyLongObject *)n, + (unsigned char*)key, keysize * sizeof(PY_UINT32_T), + 1 /* little-endian */, + 0 /* unsigned */) == 0) { +#ifdef WORDS_BIGENDIAN + /* swap bytes in 32-bit chunks */ + size_t i; + for (i = 0; i < keysize; i++) { + PY_UINT32_T v = key[i]; + v = ((v & 0x00FF00FFu) << 8) | ((v >> 8) & 0x00FF00FFu); + key[i] = (v << 16) | (v >> 16); } - new_key = (unsigned long *)PyMem_Realloc(key, - bigger * sizeof(*key)); - if (new_key == NULL) - goto Done; - key = new_key; - keymax = bigger; +#endif + result = init_by_array(self, key, keysize); } - assert(keyused < keymax); - key[keyused++] = chunk; + PyMem_Free(key); } - - if (keyused == 0) - key[keyused++] = 0UL; - result = init_by_array(self, key, keyused); + else { + PY_UINT32_T zerokey = 0; + result = init_by_array(self, &zerokey, 1); + } Done: - Py_XDECREF(masklower); - Py_XDECREF(thirtytwo); Py_XDECREF(n); - PyMem_Free(key); return result; }