New submission from Steven Barker:

The C implementation of `_random.Random.getrandbits` is unnecessarily limited 
in the number of bits it can produce on 64-bit Windows systems. I learned about 
this issue in discussion of my answer to this stack overflow question:

 
http://stackoverflow.com/questions/37356338/is-there-a-predictable-replacement-for-os-urandom-using-pythons-random-module

The argument parsing code in `getrandbits` forces its Python `int` argument to 
fit into a C `int` variable. On my 64-bit Windows system, any value larger than 
`2**31-1` causes a `OverflowError`.

Since the number of bits is directly related to how much memory we need to 
allocate (in the non-fast case), I think `Py_ssize_t` would be more appropriate 
type than a regular `int`. This probably isn't an issue on non-Windows or 
64-bit systems, where `int` and `Py_ssize_t` will have the same size.

I'm attaching a very simple patch that changes the types of the relevant 
variables and the format code in the call to `PyArg_ParseTuple`. The code works 
and still passes its tests with the patch. I considered adding an additional 
test for this issue, but passing test cases would require allocations of 
several gigabytes of memory which seems a rather unfriendly thing to add in a 
test for a fairly minor issue.

This issue doesn't effect the pure Python implementation of 
`random.SystemRandom.getrandbits`, which already worked fine when large numbers 
of bits were requested. The documentation for `random.getrandbits` doesn't 
mention any limitation on the number of bits provided, so I don't imagine there 
will be backwards compatibility issues. I also don't expect the change to have 
any impact on third party `Random` replacement classes.

For convenience, here's the contents of the very short patch (which I'll also 
attach):

diff --git a/Modules/_randommodule.c b/Modules/_randommodule.c
index fd6b230..3bf564f 100644
--- a/Modules/_randommodule.c
+++ b/Modules/_randommodule.c
@@ -348,12 +348,12 @@ random_setstate(RandomObject *self, PyObject *state)
 static PyObject *
 random_getrandbits(RandomObject *self, PyObject *args)
 {
-    int k, i, words;
+    Py_ssize_t k, i, words;
     PY_UINT32_T r;
     PY_UINT32_T *wordarray;
     PyObject *result;

-    if (!PyArg_ParseTuple(args, "i:getrandbits", &k))
+    if (!PyArg_ParseTuple(args, "n:getrandbits", &k))
         return NULL;

     if (k <= 0) {

----------
components: Library (Lib)
files: getrandbits.diff
keywords: patch
messages: 265987
nosy: Steven.Barker
priority: normal
severity: normal
status: open
title: random.getrandbits is limited to 2**31-1 bits on 64-bit Windows
type: enhancement
versions: Python 3.6
Added file: http://bugs.python.org/file42919/getrandbits.diff

_______________________________________
Python tracker <rep...@bugs.python.org>
<http://bugs.python.org/issue27072>
_______________________________________
_______________________________________________
Python-bugs-list mailing list
Unsubscribe: 
https://mail.python.org/mailman/options/python-bugs-list/archive%40mail-archive.com

Reply via email to