diff -r a0421b30a841 Modules/_randommodule.c --- a/Modules/_randommodule.c Sun Nov 18 10:42:42 2012 +0000 +++ b/Modules/_randommodule.c Sun Nov 18 15:28:29 2012 +0000 @@ -207,13 +207,12 @@ 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; + unsigned long *key = NULL; + unsigned char *key_as_bytes = NULL; + unsigned long keyused, i; + size_t bits; + int res; PyObject *arg = NULL; @@ -243,69 +242,43 @@ 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) + /* Figure out how many 32-bit chunks this gives us. */ + if (bits / 32 >= UINT_MAX) { + PyErr_SetString(PyExc_ValueError, + "seed value too large"); goto Done; - thirtytwo = PyLong_FromLong(32L); - if (thirtytwo == NULL) + } + else + keyused = bits == 0 ? 1 : (bits - 1) / 32 + 1; + + /* Convert seed to byte sequence. */ + key_as_bytes = (unsigned char *)PyMem_Malloc(keyused * 4); + res = _PyLong_AsByteArray((PyLongObject *)n, + key_as_bytes, keyused * 4, + 1, /* little-endian */ + 0); /* unsigned */ + if (res == -1) { + PyMem_Free(key_as_bytes); 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; - } - new_key = (unsigned long *)PyMem_Realloc(key, - bigger * sizeof(*key)); - if (new_key == NULL) - goto Done; - key = new_key; - keymax = bigger; - } - assert(keyused < keymax); - key[keyused++] = chunk; } - - if (keyused == 0) - key[keyused++] = 0UL; + + /* Fill array of unsigned longs from byte sequence. */ + key = (unsigned long *)PyMem_Malloc(keyused * sizeof(unsigned long)); + for (i = 0; i < keyused; i++) { + key[i] = + ((unsigned long)key_as_bytes[4*i + 0] << 0) + + ((unsigned long)key_as_bytes[4*i + 1] << 8) + + ((unsigned long)key_as_bytes[4*i + 2] << 16) + + ((unsigned long)key_as_bytes[4*i + 3] << 24); + } + PyMem_Free(key_as_bytes); result = init_by_array(self, key, keyused); Done: - Py_XDECREF(masklower); - Py_XDECREF(thirtytwo); Py_XDECREF(n); PyMem_Free(key); return result;