Use rb_len_t for byte lengths in random.c

Random.urandom converts its size with NUM2LEN instead of the unsigned macro, so a negative Integer raises ArgumentError without wrapping through the whole unsigned range first, and a size beyond the signed range raises RangeError the way Random#bytes already does. Neither error was covered before.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
Hiroshi SHIBATA 2026-09-18 07:43:07 +09:00
parent 94f16320f7
commit fa1bbf4163
Notes: git 2026-10-09 05:02:04 +00:00
2 changed files with 19 additions and 9 deletions

View File

@ -726,7 +726,7 @@ random_seed(VALUE _)
static VALUE
random_raw_seed(VALUE self, VALUE size)
{
long n = NUM2ULONG(size);
rb_len_t n = NUM2LEN(size);
VALUE buf = rb_str_new(0, n);
if (n == 0) return buf;
if (fill_random_bytes(RSTRING_PTR(buf), n, TRUE))
@ -1036,17 +1036,17 @@ rb_genrand_ulong_limited(unsigned long limit)
}
static VALUE
obj_random_bytes(VALUE obj, void *p, long n)
obj_random_bytes(VALUE obj, void *p, rb_len_t n)
{
VALUE len = LONG2NUM(n);
VALUE len = LEN2NUM(n);
VALUE v = rb_funcallv_public(obj, id_bytes, 1, &len);
long l;
rb_len_t l;
Check_Type(v, T_STRING);
l = RSTRING_LEN(v);
if (l < n)
rb_raise(rb_eRangeError, "random data too short %ld", l);
rb_raise(rb_eRangeError, "random data too short %"PRIdLEN, l);
else if (l > n)
rb_raise(rb_eRangeError, "random data too long %ld", l);
rb_raise(rb_eRangeError, "random data too long %"PRIdLEN, l);
if (p) memcpy(p, RSTRING_PTR(v), n);
return v;
}
@ -1211,7 +1211,7 @@ random_ulong_limited_big(VALUE obj, const rb_random_interface_t *rng, rb_random_
}
static VALUE
rand_bytes(const rb_random_interface_t *rng, rb_random_t *rnd, long n)
rand_bytes(const rb_random_interface_t *rng, rb_random_t *rnd, rb_len_t n)
{
VALUE bytes;
char *ptr;
@ -1235,7 +1235,7 @@ random_bytes(VALUE obj, VALUE len)
{
const rb_random_interface_t *rng = NULL;
rb_random_t *rnd = try_get_rnd(obj, &rng);
return rand_bytes(rng, rnd, NUM2LONG(rb_to_int(len)));
return rand_bytes(rng, rnd, NUM2LEN(rb_to_int(len)));
}
void
@ -1282,7 +1282,7 @@ static VALUE
random_s_bytes(VALUE obj, VALUE len)
{
rb_random_t *rnd = default_rand_start();
return rand_bytes(&random_mt_if, rnd, NUM2LONG(rb_to_int(len)));
return rand_bytes(&random_mt_if, rnd, NUM2LEN(rb_to_int(len)));
}
/*

View File

@ -1,5 +1,6 @@
# frozen_string_literal: false
require 'test/unit'
require 'rbconfig/sizeof'
class TestRand < Test::Unit::TestCase
def assert_random_int(m, init = 0, iterate: 5)
@ -423,6 +424,15 @@ class TestRand < Test::Unit::TestCase
end
end
def test_urandom_size_errors
beyond_long = 2 ** (RbConfig::SIZEOF['long'] * 8 - 1)
assert_raise(ArgumentError) { Random.urandom(-1) }
assert_raise(RangeError) { Random.urandom(beyond_long) }
# Random#bytes converts its size the same way, so the classes have to agree
assert_raise(ArgumentError) { Random.new.bytes(-1) }
assert_raise(RangeError) { Random.new.bytes(beyond_long) }
end
def test_new_seed
size = 0
n = 8