From 34d4dab683c69578b0ddd1725290529dd812b291 Mon Sep 17 00:00:00 2001 From: Macarthur Inbody <133794m3r@gmail.com> Date: Wed, 23 Dec 2020 12:05:26 -0500 Subject: [PATCH] extmod/modurandom: Add error message when getrandbits has bad value. The random module's getrandbits() method didn't give a proper error message when calling it with a value that was outside of the range of 1-32, which can lead to confusion using this function (which under CPython can accept numbers larger than 32). Now instead of simply giving a ValueError it gives an error message that states that the number of bits is constrained. Also, since the random module's functions getrandbits() and randint() differ from CPython, tests have been added to describe these differences. For getrandbits the relevant documentation is shown and added to the docs. The same is given for randint method so that the information is more easily found. Finally, since the int object lacks the bit_length() method there is a test for that method also to include within the docs, showing the difference to CPython. --- extmod/modurandom.c | 2 +- tests/cpydiff/modules_random_getrandbits.py | 12 ++++++++++++ tests/cpydiff/modules_random_randint.py | 12 ++++++++++++ tests/cpydiff/types_int_bit_length.py | 9 +++++++++ 4 files changed, 34 insertions(+), 1 deletion(-) create mode 100644 tests/cpydiff/modules_random_getrandbits.py create mode 100644 tests/cpydiff/modules_random_randint.py create mode 100644 tests/cpydiff/types_int_bit_length.py diff --git a/extmod/modurandom.c b/extmod/modurandom.c index 5a736c1ebc..f44510be9b 100644 --- a/extmod/modurandom.c +++ b/extmod/modurandom.c @@ -88,7 +88,7 @@ STATIC uint32_t yasmarang_randbelow(uint32_t n) { STATIC mp_obj_t mod_urandom_getrandbits(mp_obj_t num_in) { int n = mp_obj_get_int(num_in); if (n > 32 || n == 0) { - mp_raise_ValueError(NULL); + mp_raise_ValueError(MP_ERROR_TEXT("bits must be 32 or less")); } uint32_t mask = ~0; // Beware of C undefined behavior when shifting by >= than bit size diff --git a/tests/cpydiff/modules_random_getrandbits.py b/tests/cpydiff/modules_random_getrandbits.py new file mode 100644 index 0000000000..523e3a329d --- /dev/null +++ b/tests/cpydiff/modules_random_getrandbits.py @@ -0,0 +1,12 @@ +""" +categories: Modules,random +description: ``getrandbits`` method can only return a maximum of 32 bits at a time. +cause: PRNG's internal state is only 32bits so it can only return a maximum of 32 bits of data at a time. +workaround: If you need a number that has more than 32 bits then utilize the random module from micropython-lib. +""" + +import random + + +x = random.getrandbits(64) +print("{}".format(x)) diff --git a/tests/cpydiff/modules_random_randint.py b/tests/cpydiff/modules_random_randint.py new file mode 100644 index 0000000000..b05908a157 --- /dev/null +++ b/tests/cpydiff/modules_random_randint.py @@ -0,0 +1,12 @@ +""" +categories: Modules,random +description: ``randint`` method can only return an integer that is at most the native word size. +cause: PRNG is only able to generate 32 bits of state at a time. The result is then cast into a native sized int instead of a full int object. +workaround: If you need integers larger than native wordsize use the random module from micropython-lib. +""" + +import random + + +x = random.randint(2 ** 128 - 1, 2 ** 128) +print("x={}".format(x)) diff --git a/tests/cpydiff/types_int_bit_length.py b/tests/cpydiff/types_int_bit_length.py new file mode 100644 index 0000000000..2e907745a9 --- /dev/null +++ b/tests/cpydiff/types_int_bit_length.py @@ -0,0 +1,9 @@ +""" +categories: Types,int +description: ``bit_length`` method doesn't exist. +cause: bit_length method is not implemented. +workaround: Avoid using this method on MicroPython. +""" + +x = 255 +print("{} is {} bits long.".format(x, x.bit_length()))