Skip to content

Commit

Permalink
[Bug #19100] Add init_int32 function to rb_random_interface_t
Browse files Browse the repository at this point in the history
Distinguish initialization by single word from initialization by
array.
  • Loading branch information
nobu committed Nov 10, 2022
1 parent 6eaed20 commit b7e8876
Show file tree
Hide file tree
Showing 5 changed files with 51 additions and 12 deletions.
3 changes: 3 additions & 0 deletions ext/-test-/random/bad_version.c
Expand Up @@ -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)
Expand Down
1 change: 1 addition & 0 deletions ext/-test-/random/loop.c
Expand Up @@ -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)
{
Expand Down
30 changes: 26 additions & 4 deletions include/ruby/random.h
Expand Up @@ -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
Expand Down Expand Up @@ -66,6 +66,17 @@ RBIMPL_ATTR_NONNULL(())
*/
typedef void rb_random_init_func(rb_random_t *rng, const uint32_t *buf, size_t len);

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.
Expand Down Expand Up @@ -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;

Expand Down Expand Up @@ -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)

Expand Down Expand Up @@ -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

Expand All @@ -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
Expand Down
21 changes: 13 additions & 8 deletions random.c
Expand Up @@ -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;
Expand Down Expand Up @@ -891,16 +894,18 @@ rand_mt_load(VALUE obj, VALUE dump)
return obj;
}

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
Expand Down
8 changes: 8 additions & 0 deletions test/ruby/test_rand.rb
Expand Up @@ -336,6 +336,14 @@ def test_seed
}
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) {
Expand Down

0 comments on commit b7e8876

Please sign in to comment.