random: randint() no longer rejects the largest upper bound - #11443
Merged
Merged
Conversation
adafruit#11378 made `randint(a, b)` raise `ValueError` when `b` is the largest `mp_int_t`, to avoid the `b + 1` overflow in `randrange(a, b + 1, 1)`. On 32-bit ports that is `0x7FFFFFFF`, which the WIZnet DHCP library passes, so `randint(1, 0x7FFFFFFF)` stopped working (adafruit#11441). Add `shared_modules_random_randint()`, which computes the span `b - a + 1` in unsigned arithmetic so it cannot overflow for any `a <= b`, and use it from the binding instead of forming `b + 1`. Fixes adafruit#11441 Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Member
|
Want this on 10.3.x instead? |
Collaborator
Author
The issue says this works in 10.3.1, and the code that caused the regression was only on |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Code written by Claude Code, guided and corrected by @dhalbert.
The problem
#11378 (FYI @peterbay) made
randint(a, b)raiseValueErrorwhenbis the largestmp_int_t, to avoid theb + 1overflow in therandrange(a, b + 1, 1)it called. On 32-bit ports that value is0x7FFFFFFF, which is a perfectly ordinary upper bound. Andrandint(1, 0x7FFFFFFF)is what the WIZnet DHCP library uses for its transaction id.The changes
shared_modules_random_randint()inshared-module/random/__init__.c. It computes the spanb - a + 1inmp_uint_t, so it cannot overflow for anya <= b, and draws withyasmarang_randbelow()directly. A span of zero (the fullmp_int_trange) returns a raw 32-bit draw instead of looping forever inrandbelow(). In practicemp_obj_get_int()already rejects the most negativemp_int_t, so that branch is a guard rather than a reachable path.random.randint()inshared-bindings/random/__init__.ccalls it and drops both theb + 1and theb == INT_MAXcheck. Thea > bcheck is unchanged.CIRCUITPY-CHANGEblock intests/extmod/random_extra.pyexercisingrandint(0, 0x7FFFFFFF)andrandint(1, 0x7FFFFFFF). The unix test build is 64-bit, so this only catches the regression on 32-bit targets, but it documents the requirement.Testing
Feather nRF52840 Express, before and after.
randint(1, 0x7FFFFFFF)ValueErrorrandint(0, 0x7FFFFFFF)ValueErrorrandint(-1, 0x7FFFFFFF)ValueErrorrandint(-0x7FFFFFFF, 0x7FFFFFFF)ValueErrorseed(7)twice, thenrandint(0, 0x7FFFFFFF)ValueErrorrandint(5, 5),randint(-3, -3)5,-35,-3randint(2, 1)ValueErrorValueErrortests/extmod/random_*.pypass on the unix coverage build.