random.c: use bytes
* random.c (obj_random_bytes): base on bytes method instead of rand method, not to call toplevel rand method. git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@54968 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
This commit is contained in:
parent
518713fd65
commit
b402cc7161
@ -1,3 +1,8 @@
|
|||||||
|
Tue May 10 14:57:09 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
|
||||||
|
|
||||||
|
* random.c (obj_random_bytes): base on bytes method instead of
|
||||||
|
rand method, not to call toplevel rand method.
|
||||||
|
|
||||||
Tue May 10 13:07:28 2016 NARUSE, Yui <naruse@ruby-lang.org>
|
Tue May 10 13:07:28 2016 NARUSE, Yui <naruse@ruby-lang.org>
|
||||||
|
|
||||||
* configure.in (-fexcess-precision=standard): before r54895 -std=c99
|
* configure.in (-fexcess-precision=standard): before r54895 -std=c99
|
||||||
|
@ -75,6 +75,10 @@ module SecureRandom
|
|||||||
ret
|
ret
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
class << self
|
||||||
|
alias bytes gen_random
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
module Random::Formatter
|
module Random::Formatter
|
||||||
|
85
random.c
85
random.c
@ -898,17 +898,20 @@ rb_genrand_ulong_limited(unsigned long limit)
|
|||||||
return limited_rand(default_mt(), limit);
|
return limited_rand(default_mt(), limit);
|
||||||
}
|
}
|
||||||
|
|
||||||
static unsigned int
|
static VALUE
|
||||||
obj_random_int32(VALUE obj)
|
obj_random_bytes(VALUE obj, void *p, long n)
|
||||||
{
|
{
|
||||||
#if SIZEOF_LONG * CHAR_BIT > 32
|
VALUE len = LONG2NUM(n);
|
||||||
VALUE lim = ULONG2NUM(0x100000000UL);
|
VALUE v = rb_funcallv_public(obj, id_bytes, 1, &len);
|
||||||
#elif defined HAVE_LONG_LONG
|
long l;
|
||||||
VALUE lim = ULL2NUM((LONG_LONG)0xffffffff+1);
|
Check_Type(v, T_STRING);
|
||||||
#else
|
l = RSTRING_LEN(v);
|
||||||
VALUE lim = rb_big_plus(ULONG2NUM(0xffffffff), INT2FIX(1));
|
if (l < n)
|
||||||
#endif
|
rb_raise(rb_eRangeError, "random data too short %ld", l);
|
||||||
return (unsigned int)NUM2ULONG(rb_funcall2(obj, id_rand, 1, &lim));
|
else if (l > n)
|
||||||
|
rb_raise(rb_eRangeError, "random data too long %ld", l);
|
||||||
|
if (p) memcpy(p, RSTRING_PTR(v), n);
|
||||||
|
return v;
|
||||||
}
|
}
|
||||||
|
|
||||||
static unsigned int
|
static unsigned int
|
||||||
@ -922,7 +925,9 @@ rb_random_int32(VALUE obj)
|
|||||||
{
|
{
|
||||||
rb_random_t *rnd = try_get_rnd(obj);
|
rb_random_t *rnd = try_get_rnd(obj);
|
||||||
if (!rnd) {
|
if (!rnd) {
|
||||||
return obj_random_int32(obj);
|
uint32_t x;
|
||||||
|
obj_random_bytes(obj, &x, sizeof(x));
|
||||||
|
return (unsigned int)x;
|
||||||
}
|
}
|
||||||
return random_int32(rnd);
|
return random_int32(rnd);
|
||||||
}
|
}
|
||||||
@ -933,8 +938,10 @@ random_real(VALUE obj, rb_random_t *rnd, int excl)
|
|||||||
uint32_t a, b;
|
uint32_t a, b;
|
||||||
|
|
||||||
if (!rnd) {
|
if (!rnd) {
|
||||||
a = obj_random_int32(obj);
|
uint32_t x[2] = {0, 0};
|
||||||
b = obj_random_int32(obj);
|
obj_random_bytes(obj, x, sizeof(x));
|
||||||
|
a = x[0];
|
||||||
|
b = x[1];
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
a = random_int32(rnd);
|
a = random_int32(rnd);
|
||||||
@ -982,6 +989,22 @@ ulong_to_num_plus_1(unsigned long n)
|
|||||||
static unsigned long
|
static unsigned long
|
||||||
random_ulong_limited(VALUE obj, rb_random_t *rnd, unsigned long limit)
|
random_ulong_limited(VALUE obj, rb_random_t *rnd, unsigned long limit)
|
||||||
{
|
{
|
||||||
|
if (!limit) return 0;
|
||||||
|
if (!rnd) {
|
||||||
|
unsigned long val, mask = make_mask(limit);
|
||||||
|
do {
|
||||||
|
obj_random_bytes(obj, &val, sizeof(unsigned long));
|
||||||
|
val &= mask;
|
||||||
|
} while (limit < val);
|
||||||
|
return val;
|
||||||
|
}
|
||||||
|
return limited_rand(&rnd->mt, limit);
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned long
|
||||||
|
rb_random_ulong_limited(VALUE obj, unsigned long limit)
|
||||||
|
{
|
||||||
|
rb_random_t *rnd = try_get_rnd(obj);
|
||||||
if (!rnd) {
|
if (!rnd) {
|
||||||
VALUE lim = ulong_to_num_plus_1(limit);
|
VALUE lim = ulong_to_num_plus_1(limit);
|
||||||
VALUE v = rb_to_int(rb_funcall2(obj, id_rand, 1, &lim));
|
VALUE v = rb_to_int(rb_funcall2(obj, id_rand, 1, &lim));
|
||||||
@ -1001,25 +1024,31 @@ static VALUE
|
|||||||
random_ulong_limited_big(VALUE obj, rb_random_t *rnd, VALUE vmax)
|
random_ulong_limited_big(VALUE obj, rb_random_t *rnd, VALUE vmax)
|
||||||
{
|
{
|
||||||
if (!rnd) {
|
if (!rnd) {
|
||||||
VALUE lim = rb_big_plus(vmax, INT2FIX(1));
|
VALUE v, vtmp;
|
||||||
VALUE v = rb_to_int(rb_funcall2(obj, id_rand, 1, &lim));
|
size_t i, nlz, len = rb_absint_numwords(vmax, 32, &nlz);
|
||||||
if (rb_num_negative_p(v)) {
|
uint32_t *tmp = ALLOCV_N(uint32_t, vtmp, len * 2);
|
||||||
rb_raise(rb_eRangeError, "random number too small %"PRIsVALUE, v);
|
uint32_t mask = (uint32_t)~0 >> nlz;
|
||||||
}
|
uint32_t *lim_array = tmp;
|
||||||
if (FIX2LONG(rb_big_cmp(vmax, v)) < 0) {
|
uint32_t *rnd_array = tmp + len;
|
||||||
rb_raise(rb_eRangeError, "random number too big %"PRIsVALUE, v);
|
int flag = INTEGER_PACK_MSWORD_FIRST|INTEGER_PACK_NATIVE_BYTE_ORDER;
|
||||||
|
rb_integer_pack(vmax, lim_array, len, sizeof(uint32_t), 0, flag);
|
||||||
|
|
||||||
|
retry:
|
||||||
|
obj_random_bytes(obj, rnd_array, len * sizeof(uint32_t));
|
||||||
|
rnd_array[0] &= mask;
|
||||||
|
for (i = 0; i < len; ++i) {
|
||||||
|
if (lim_array[i] < rnd_array[i])
|
||||||
|
goto retry;
|
||||||
|
if (rnd_array[i] < lim_array[i])
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
v = rb_integer_unpack(rnd_array, len, sizeof(uint32_t), 0, flag);
|
||||||
|
ALLOCV_END(vtmp);
|
||||||
return v;
|
return v;
|
||||||
}
|
}
|
||||||
return limited_big_rand(&rnd->mt, vmax);
|
return limited_big_rand(&rnd->mt, vmax);
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned long
|
|
||||||
rb_random_ulong_limited(VALUE obj, unsigned long limit)
|
|
||||||
{
|
|
||||||
return random_ulong_limited(obj, try_get_rnd(obj), limit);
|
|
||||||
}
|
|
||||||
|
|
||||||
static VALUE genrand_bytes(rb_random_t *rnd, long n);
|
static VALUE genrand_bytes(rb_random_t *rnd, long n);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -1068,8 +1097,7 @@ rb_random_bytes(VALUE obj, long n)
|
|||||||
{
|
{
|
||||||
rb_random_t *rnd = try_get_rnd(obj);
|
rb_random_t *rnd = try_get_rnd(obj);
|
||||||
if (!rnd) {
|
if (!rnd) {
|
||||||
VALUE len = LONG2NUM(n);
|
return obj_random_bytes(obj, NULL, n);
|
||||||
return rb_funcall2(obj, id_bytes, 1, &len);
|
|
||||||
}
|
}
|
||||||
return genrand_bytes(rnd, n);
|
return genrand_bytes(rnd, n);
|
||||||
}
|
}
|
||||||
@ -1601,6 +1629,7 @@ InitVM_Random(void)
|
|||||||
VALUE m = rb_define_module_under(rb_cRandom, "Formatter");
|
VALUE m = rb_define_module_under(rb_cRandom, "Formatter");
|
||||||
rb_include_module(rb_cRandom, m);
|
rb_include_module(rb_cRandom, m);
|
||||||
rb_define_method(m, "random_number", rand_random_number, -1);
|
rb_define_method(m, "random_number", rand_random_number, -1);
|
||||||
|
rb_define_method(m, "rand", rand_random_number, -1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -526,6 +526,17 @@ END
|
|||||||
assert_equal(2, gen.limit, bug7935)
|
assert_equal(2, gen.limit, bug7935)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def test_random_ulong_limited_no_rand
|
||||||
|
c = Class.new do
|
||||||
|
undef rand
|
||||||
|
def bytes(n)
|
||||||
|
"\0"*n
|
||||||
|
end
|
||||||
|
end
|
||||||
|
gen = c.new.extend(Random::Formatter)
|
||||||
|
assert_equal(1, [1, 2].sample(random: gen))
|
||||||
|
end
|
||||||
|
|
||||||
def test_default_seed
|
def test_default_seed
|
||||||
assert_separately([], <<-End)
|
assert_separately([], <<-End)
|
||||||
seed = Random::DEFAULT::seed
|
seed = Random::DEFAULT::seed
|
||||||
|
@ -157,6 +157,20 @@ end
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def test_s_random_number_not_default
|
||||||
|
msg = "SecureRandom#random_number should not be affected by srand"
|
||||||
|
seed = srand(0)
|
||||||
|
x = @it.random_number(1000)
|
||||||
|
10.times do|i|
|
||||||
|
srand(0)
|
||||||
|
return unless @it.random_number(1000) == x
|
||||||
|
end
|
||||||
|
srand(0)
|
||||||
|
assert_not_equal(x, @it.random_number(1000), msg)
|
||||||
|
ensure
|
||||||
|
srand(seed) if seed
|
||||||
|
end
|
||||||
|
|
||||||
def test_uuid
|
def test_uuid
|
||||||
uuid = @it.uuid
|
uuid = @it.uuid
|
||||||
assert_equal(36, uuid.size)
|
assert_equal(36, uuid.size)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user