Skip to content

Possible unnecessary OverflowError in random.getrandbits #133489

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
Nokhrin opened this issue May 6, 2025 · 11 comments
Closed

Possible unnecessary OverflowError in random.getrandbits #133489

Nokhrin opened this issue May 6, 2025 · 11 comments
Assignees
Labels
extension-modules C modules in the Modules dir type-bug An unexpected behavior, bug, or error

Comments

@Nokhrin
Copy link

Nokhrin commented May 6, 2025

Documentation

Problem

Actual upper bound of a random.Random.randbytes is 2**28 - 1

Following docs and exception message I would expect the limit of 2 ** 32 - 1 as for C 4-bytes integer

    ## -------------------- bytes methods ---------------------

    def randbytes(self, n):
        """Generate n random bytes."""
        return self.getrandbits(n * 8).to_bytes(n, 'little')
>>> bytes_string = random.randbytes(2 ** 28)
Traceback (most recent call last):
  File "C:\Program Files\Python39\lib\code.py", line 90, in runcode
    exec(code, self.locals)
  File "<input>", line 1, in <module>
  File "C:\Program Files\Python39\lib\random.py", line 286, in randbytes
    return self.getrandbits(n * 8).to_bytes(n, 'little')
OverflowError: Python int too large to convert to C int
>>> bytes_string = random.randbytes(2 ** 28 - 1)
>>> len(bytes_string)
268435455

Reproduced on
Python 3.9.4 (tags/v3.9.4:1f2e308, Apr 6 2021, 13:40:21) [MSC v.1928 64 bit (AMD64)] on win32
Python 3.11.2 (main, Jul 19 2024, 12:24:02) [GCC 12.2.0] on linux

Will you please point me - if there is a bug in docs/implementation, or this is my misunderstanding only.
Thank you in advance for you patience.

Linked PRs

@rhettinger
Copy link
Contributor

@serhiy-storchaka The overflow occurs in the upstream call to random.getrandbits(8 * 2 ** 28 - 1).

The argument clinic spec reads:

_random.Random.getrandbits

  self: self(type="RandomObject *")
  k: int
  /

Should k be switched to object and converted with PyLong_AsLongLongAndOverflow? The 32-bit signed int limitation on Windows seems unnecessarily restrictive.

@rhettinger rhettinger changed the title Clarification on Random.randbytes docs Possible unnecessary OverflowError in getrandbits May 6, 2025
@rhettinger rhettinger added type-feature A feature request or enhancement and removed docs Documentation in the Doc dir labels May 6, 2025
@rhettinger rhettinger changed the title Possible unnecessary OverflowError in getrandbits Possible unnecessary OverflowError in random.getrandbits May 6, 2025
@rhettinger rhettinger added type-bug An unexpected behavior, bug, or error and removed type-feature A feature request or enhancement labels May 6, 2025
@skirpichev
Copy link
Contributor

Why not have int32 converter in the AC? Now we have PyLong_AsInt32/AsUInt32/etc.

@picnixz picnixz added the extension-modules C modules in the Modules dir label May 7, 2025
@rhettinger
Copy link
Contributor

rhettinger commented May 7, 2025

@skirpichev We want something like ssize_t so that we can ask for arrays as big as we can allocate. The limit should be driven by memory constraints rather than function argument constraints. 32-bit signed is insufficient.

@serhiy-storchaka
Copy link
Member

Why not have int32 converter in the AC?

It was in my plans.

For this case it is better to use the size_t converter (automatic ValueError for negative value), or even the uint64 converter (to be able creating bytes objects up to 2 GiB on 32-bit platforms).

@skirpichev
Copy link
Contributor

or even the uint64 converter

Yes, int32 was just a typo - I meant converters for fixed-size (unsigned) integers. 8-byte type looks better, of course, for the given case.

@serhiy-storchaka
Copy link
Member

See #133583.

serhiy-storchaka added a commit to serhiy-storchaka/cpython that referenced this issue May 8, 2025
…tes()

random.getrandbits() can now generate more that 2**31 bits.
random.randbytes() can now generate more that 256 MiB.
@serhiy-storchaka
Copy link
Member

#133658 makes getrandbits() using 64-bit bits count. Since in CPython a hard limit for bits count in integers is 64-bit, this is the right type.

What should we do with other versions, @Raymond? I think that it is not late to backport it to 3.14, and the backport is strightforward, because the uint64 converter exists in 3.14. In 3.13 we could use unsigned_long_long, which is practically the same. Or we can document the limitation if it is too late for backport.

@gpshead
Copy link
Member

gpshead commented May 31, 2025

raising OverflowError feels like a bug so back porting all the way to 3.13 as a bug fix makes sense to me.

serhiy-storchaka added a commit that referenced this issue May 31, 2025
…H-133658)

random.getrandbits() can now generate more that 2**31 bits.
random.randbytes() can now generate more that 256 MiB.
miss-islington pushed a commit to miss-islington/cpython that referenced this issue May 31, 2025
…tes() (pythonGH-133658)

random.getrandbits() can now generate more that 2**31 bits.
random.randbytes() can now generate more that 256 MiB.
(cherry picked from commit 68784fe)

Co-authored-by: Serhiy Storchaka <[email protected]>
serhiy-storchaka added a commit to serhiy-storchaka/cpython that referenced this issue May 31, 2025
… randbytes() (pythonGH-133658)

random.getrandbits() can now generate more that 2**31 bits.
random.randbytes() can now generate more that 256 MiB.
(cherry picked from commit 68784fe)

Co-authored-by: Serhiy Storchaka <[email protected]>
gpshead pushed a commit that referenced this issue Jun 1, 2025
…ytes() (GH-133658) (#134964)

gh-133489: Remove size restrictions on getrandbits() and randbytes() (GH-133658)

random.getrandbits() can now generate more that 2**31 bits.
random.randbytes() can now generate more that 256 MiB.
(cherry picked from commit 68784fe)

Co-authored-by: Serhiy Storchaka <[email protected]>
serhiy-storchaka added a commit that referenced this issue Jun 2, 2025
…ytes() (GH-133658) (GH-134965)

random.getrandbits() can now generate more that 2**31 bits.
random.randbytes() can now generate more that 256 MiB.
(cherry picked from commit 68784fe)
@tornaria
Copy link

tornaria commented Jun 9, 2025

There is an (unintended?) api break. In python 3.13.3, getrandbits() accepts an "integer-like" object as in:

Python 3.13.3 (main, Apr 11 2025, 13:41:26) [GCC 13.2.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import random ; r = random.Random()
>>> from numpy import int64
>>> r.getrandbits(int64(20))
582096

but in python 3.13.4, getrandbits() fails as in:

Python 3.13.4 (main, Jun  8 2025, 19:43:01) [GCC 14.2.1 20250405] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import random ; r = random.Random()
>>> from numpy import int64
>>> r.getrandbits(int64(20))
Traceback (most recent call last):
  File "<python-input-2>", line 1, in <module>
    r.getrandbits(int64(20))
    ~~~~~~~~~~~~~^^^^^^^^^^^
TypeError: an integer is required

This causes trouble for sagemath, where integers are by default a special type ZZ.

@gpshead
Copy link
Member

gpshead commented Jun 9, 2025

Can you please open a new issue to track that?

@skirpichev
Copy link
Contributor

Ah, that's because _PyLong_UnsignedLongLong_Converter() has no fallback to index-like objects.

In 3.14+ we are using PyLong_AsNativeBytes for uint64 converter and it's not an issue. Maybe just add a uint64 converter for 3.13 (it has PyLong_AsNativeBytes) or this is too much?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
extension-modules C modules in the Modules dir type-bug An unexpected behavior, bug, or error
Projects
Status: Todo
Development

Successfully merging a pull request may close this issue.

7 participants