diff options
-rw-r--r-- | ext/-test-/random/bad_version.c | 3 | ||||
-rw-r--r-- | ext/-test-/random/loop.c | 1 | ||||
-rw-r--r-- | include/ruby/random.h | 30 | ||||
-rw-r--r-- | random.c | 21 | ||||
-rw-r--r-- | test/ruby/test_rand.rb | 8 |
5 files changed, 51 insertions, 12 deletions
diff --git a/ext/-test-/random/bad_version.c b/ext/-test-/random/bad_version.c index b6bf2ac5af..dae63a6d19 100644 --- a/ext/-test-/random/bad_version.c +++ b/ext/-test-/random/bad_version.c @@ -20,6 +20,9 @@ bad_version_init(rb_random_t *rnd, const uint32_t *buf, size_t len) must_not_reach(); } +NORETURN(static void bad_version_init_int32(rb_random_t *, uint32_t)); +RB_RANDOM_DEFINE_INIT_INT32_FUNC(bad_version) + NORETURN(static void bad_version_get_bytes(rb_random_t *, void *, size_t)); static void bad_version_get_bytes(rb_random_t *rnd, void *p, size_t n) diff --git a/ext/-test-/random/loop.c b/ext/-test-/random/loop.c index 0572096403..805c8e9122 100644 --- a/ext/-test-/random/loop.c +++ b/ext/-test-/random/loop.c @@ -13,6 +13,7 @@ static const rb_random_interface_t random_loop_if = { RB_RANDOM_INTERFACE_DEFINE_WITH_REAL(loop) }; +RB_RANDOM_DEFINE_INIT_INT32_FUNC(loop); static size_t random_loop_memsize(const void *ptr) { diff --git a/include/ruby/random.h b/include/ruby/random.h index 989445f2f9..39bdb6f3e3 100644 --- a/include/ruby/random.h +++ b/include/ruby/random.h @@ -19,7 +19,7 @@ /* * version * 0: before versioning; deprecated - * 1: added version and flags + * 1: added version, flags and init_32bit function */ #define RUBY_RANDOM_INTERFACE_VERSION_MAJOR 1 #define RUBY_RANDOM_INTERFACE_VERSION_MINOR 0 @@ -68,6 +68,17 @@ typedef void rb_random_init_func(rb_random_t *rng, const uint32_t *buf, size_t l RBIMPL_ATTR_NONNULL(()) /** + * This is the type of functions called when your random object is initialised. + * Passed data is the seed integer. + * + * @param[out] rng Your random struct to fill in. + * @param[in] data Seed, single word. + * @post `rng` is initialised using the passed seeds. + */ +typedef void rb_random_init_int32_func(rb_random_t *rng, uint32_t data); + +RBIMPL_ATTR_NONNULL(()) +/** * This is the type of functions called from your object's `#rand` method. * * @param[out] rng Your random struct to extract an integer from. @@ -116,9 +127,12 @@ typedef struct { */ uint16_t flags; - /** Initialiser function. */ + /** Function to initialize from uint32_t array. */ rb_random_init_func *init; + /** Function to initialize from single uint32_t. */ + rb_random_init_int32_func *init_int32; + /** Function to obtain a random integer. */ rb_random_get_int32_func *get_int32; @@ -162,11 +176,12 @@ typedef struct { } rb_random_interface_t; /** - * This utility macro defines 3 functions named prefix_init, prefix_get_int32, - * prefix_get_bytes. + * This utility macro defines 4 functions named prefix_init, prefix_init_int32, + * prefix_get_int32, prefix_get_bytes. */ #define RB_RANDOM_INTERFACE_DECLARE(prefix) \ static void prefix##_init(rb_random_t *, const uint32_t *, size_t); \ + static void prefix##_init_int32(rb_random_t *, uint32_t); \ static unsigned int prefix##_get_int32(rb_random_t *); \ static void prefix##_get_bytes(rb_random_t *, void *, size_t) @@ -195,6 +210,7 @@ typedef struct { #define RB_RANDOM_INTERFACE_DEFINE(prefix) \ RUBY_RANDOM_INTERFACE_VERSION_INITIALIZER, 0, \ prefix##_init, \ + prefix##_init_int32, \ prefix##_get_int32, \ prefix##_get_bytes @@ -206,6 +222,12 @@ typedef struct { RB_RANDOM_INTERFACE_DEFINE(prefix), \ prefix##_get_real +#define RB_RANDOM_DEFINE_INIT_INT32_FUNC(prefix) \ + static void prefix##_init_int32(rb_random_t *rnd, uint32_t data) \ + { \ + prefix##_init(rnd, &data, 1); \ + } + #if defined _WIN32 && !defined __CYGWIN__ typedef rb_data_type_t rb_random_data_type_t; # define RB_RANDOM_PARENT 0 @@ -371,11 +371,14 @@ rand_init(const rb_random_interface_t *rng, rb_random_t *rnd, VALUE seed) INTEGER_PACK_LSWORD_FIRST|INTEGER_PACK_NATIVE_BYTE_ORDER); if (sign < 0) sign = -sign; - if (len > 1) { + if (len <= 1) { + rng->init_int32(rnd, len ? buf[0] : 0); + } + else { if (sign != 2 && buf[len-1] == 1) /* remove leading-zero-guard */ len--; + rng->init(rnd, buf, len); } - rng->init(rnd, buf, len); explicit_bzero(buf, len * sizeof(*buf)); ALLOCV_END(buf0); return seed; @@ -892,15 +895,17 @@ rand_mt_load(VALUE obj, VALUE dump) } static void +rand_mt_init_int32(rb_random_t *rnd, uint32_t data) +{ + struct MT *mt = &((rb_random_mt_t *)rnd)->mt; + init_genrand(mt, data); +} + +static void rand_mt_init(rb_random_t *rnd, const uint32_t *buf, size_t len) { struct MT *mt = &((rb_random_mt_t *)rnd)->mt; - if (len <= 1) { - init_genrand(mt, len ? buf[0] : 0); - } - else { - init_by_array(mt, buf, (int)len); - } + init_by_array(mt, buf, (int)len); } static unsigned int diff --git a/test/ruby/test_rand.rb b/test/ruby/test_rand.rb index f066433f6a..a4beffd689 100644 --- a/test/ruby/test_rand.rb +++ b/test/ruby/test_rand.rb @@ -336,6 +336,14 @@ class TestRand < Test::Unit::TestCase } end + def test_seed_leading_zero_guard + guard = 1<<32 + range = 0...(1<<32) + all_assertions_foreach(nil, 0, 1, 2) do |i| + assert_not_equal(Random.new(i).rand(range), Random.new(i+guard).rand(range)) + end + end + def test_marshal bug3656 = '[ruby-core:31622]' assert_raise(TypeError, bug3656) { |