summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--extmod/modurandom.c41
-rw-r--r--tests/extmod/urandom_seed_default.py30
2 files changed, 65 insertions, 6 deletions
diff --git a/extmod/modurandom.c b/extmod/modurandom.c
index ab83b0f70..5a736c1eb 100644
--- a/extmod/modurandom.c
+++ b/extmod/modurandom.c
@@ -31,15 +31,29 @@
#if MICROPY_PY_URANDOM
+// Work out if the seed will be set on import or not.
+#if MICROPY_MODULE_BUILTIN_INIT && defined(MICROPY_PY_URANDOM_SEED_INIT_FUNC)
+#define SEED_ON_IMPORT (1)
+#else
+#define SEED_ON_IMPORT (0)
+#endif
+
// Yasmarang random number generator
// by Ilya Levin
// http://www.literatecode.com/yasmarang
// Public Domain
#if !MICROPY_ENABLE_DYNRUNTIME
+#if SEED_ON_IMPORT
+// If the state is seeded on import then keep these variables in the BSS.
+STATIC uint32_t yasmarang_pad, yasmarang_n, yasmarang_d;
+STATIC uint8_t yasmarang_dat;
+#else
+// Without seed-on-import these variables must be initialised via the data section.
STATIC uint32_t yasmarang_pad = 0xeda4baba, yasmarang_n = 69, yasmarang_d = 233;
STATIC uint8_t yasmarang_dat = 0;
#endif
+#endif
STATIC uint32_t yasmarang(void) {
yasmarang_pad += yasmarang_dat + yasmarang_d * yasmarang_n;
@@ -83,15 +97,24 @@ STATIC mp_obj_t mod_urandom_getrandbits(mp_obj_t num_in) {
}
STATIC MP_DEFINE_CONST_FUN_OBJ_1(mod_urandom_getrandbits_obj, mod_urandom_getrandbits);
-STATIC mp_obj_t mod_urandom_seed(mp_obj_t seed_in) {
- mp_uint_t seed = mp_obj_get_int_truncated(seed_in);
+STATIC mp_obj_t mod_urandom_seed(size_t n_args, const mp_obj_t *args) {
+ mp_uint_t seed;
+ if (n_args == 0 || args[0] == mp_const_none) {
+ #ifdef MICROPY_PY_URANDOM_SEED_INIT_FUNC
+ seed = MICROPY_PY_URANDOM_SEED_INIT_FUNC;
+ #else
+ mp_raise_ValueError(MP_ERROR_TEXT("no default seed"));
+ #endif
+ } else {
+ seed = mp_obj_get_int_truncated(args[0]);
+ }
yasmarang_pad = seed;
yasmarang_n = 69;
yasmarang_d = 233;
yasmarang_dat = 0;
return mp_const_none;
}
-STATIC MP_DEFINE_CONST_FUN_OBJ_1(mod_urandom_seed_obj, mod_urandom_seed);
+STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mod_urandom_seed_obj, 0, 1, mod_urandom_seed);
#if MICROPY_PY_URANDOM_EXTRA_FUNCS
@@ -189,9 +212,15 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_2(mod_urandom_uniform_obj, mod_urandom_uniform);
#endif // MICROPY_PY_URANDOM_EXTRA_FUNCS
-#ifdef MICROPY_PY_URANDOM_SEED_INIT_FUNC
+#if SEED_ON_IMPORT
STATIC mp_obj_t mod_urandom___init__() {
- mod_urandom_seed(MP_OBJ_NEW_SMALL_INT(MICROPY_PY_URANDOM_SEED_INIT_FUNC));
+ // This module may be imported by more than one name so need to ensure
+ // that it's only ever seeded once.
+ static bool seeded = false;
+ if (!seeded) {
+ seeded = true;
+ mod_urandom_seed(0, NULL);
+ }
return mp_const_none;
}
STATIC MP_DEFINE_CONST_FUN_OBJ_0(mod_urandom___init___obj, mod_urandom___init__);
@@ -200,7 +229,7 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_0(mod_urandom___init___obj, mod_urandom___init__)
#if !MICROPY_ENABLE_DYNRUNTIME
STATIC const mp_rom_map_elem_t mp_module_urandom_globals_table[] = {
{ MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_urandom) },
- #ifdef MICROPY_PY_URANDOM_SEED_INIT_FUNC
+ #if SEED_ON_IMPORT
{ MP_ROM_QSTR(MP_QSTR___init__), MP_ROM_PTR(&mod_urandom___init___obj) },
#endif
{ MP_ROM_QSTR(MP_QSTR_getrandbits), MP_ROM_PTR(&mod_urandom_getrandbits_obj) },
diff --git a/tests/extmod/urandom_seed_default.py b/tests/extmod/urandom_seed_default.py
new file mode 100644
index 000000000..a032b9362
--- /dev/null
+++ b/tests/extmod/urandom_seed_default.py
@@ -0,0 +1,30 @@
+# test urandom.seed() without any arguments
+
+try:
+ import urandom as random
+except ImportError:
+ try:
+ import random
+ except ImportError:
+ print("SKIP")
+ raise SystemExit
+
+try:
+ random.seed()
+except ValueError:
+ # no default seed on this platform
+ print("SKIP")
+ raise SystemExit
+
+
+def rng_seq():
+ return [random.getrandbits(16) for _ in range(10)]
+
+
+# seed with default and check that doesn't produce the same RNG sequence
+random.seed()
+seq = rng_seq()
+random.seed()
+print(seq == rng_seq())
+random.seed(None)
+print(seq == rng_seq())