mirror of
https://github.com/mruby/mruby
synced 2026-06-08 16:11:16 +00:00
Strict acquisition of the Random class given by mrb_get_args()
This is to prevent data corruption of the substituted `Random` instance.
If the `Object::Random` constants are redefined to a different `MRB_TT_ISTRUCT` object class, they can pass `mrb_get_args()` validation.
The following is an example of how the `Array#shuffle` method rewrites the data of a non `Random` instance.
```c
// code.c
#include <mruby.h>
#include <mruby/class.h>
#include <mruby/compile.h>
#include <mruby/istruct.h>
#define EVAL_LIT(MRB, ...) mrb_load_string((MRB), #__VA_ARGS__)
static mrb_value
fake_initialize(mrb_state *mrb, mrb_value self)
{
char *p = ISTRUCT_PTR(self);
for (int i = 0; i < ISTRUCT_DATA_SIZE; i++) {
p[i] = 'A' + i;
}
return self;
}
static mrb_value
fake_to_bytes(mrb_state *mrb, mrb_value self)
{
const char *p = ISTRUCT_PTR(self);
return mrb_str_new(mrb, p, ISTRUCT_DATA_SIZE);
}
int
main(int argc, char *argv[])
{
mrb_state *mrb = mrb_open();
struct RClass *fake = mrb_define_class(mrb, "Fake", mrb->object_class);
MRB_SET_INSTANCE_TT(fake, MRB_TT_ISTRUCT);
mrb_define_method(mrb, fake, "initialize", fake_initialize, MRB_ARGS_NONE());
mrb_define_method(mrb, fake, "to_bytes", fake_to_bytes, MRB_ARGS_NONE());
EVAL_LIT(mrb,
Random = Fake \n
fake = Fake.new \n
p [fake, fake.to_bytes] \n
p a = (1..10).to_a \n
p a.shuffle(fake) \n
p [fake, fake.to_bytes]
);
mrb_close(mrb);
return 0;
}
```
```console
% `bin/mruby-config --cc --cflags --ldflags` code.c `bin/mruby-config --libs`
% ./a.out
[#<Fake:0x8007d8f20>, "ABCDEFGHIJKLMNOPQRSTUVWX"]
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
[1, 7, 8, 10, 2, 6, 9, 3, 4, 5]
[#<Fake:0x8007d8f20>, "\xe81{\v\fM\xb0D<\x99\xb1V+l\x84\x86QRSTUVWX"]
```
This commit is contained in:
@@ -167,6 +167,7 @@ random_default(mrb_state *mrb) {
|
||||
|
||||
#define random_ptr(v) (rand_state*)mrb_istruct_ptr(v)
|
||||
#define random_default_state(mrb) random_ptr(random_default(mrb))
|
||||
#define ID_RANDOM_STRICT MRB_SYM(mruby_Random)
|
||||
|
||||
static mrb_value
|
||||
random_m_init(mrb_state *mrb, mrb_value self)
|
||||
@@ -245,7 +246,7 @@ mrb_ary_shuffle_bang(mrb_state *mrb, mrb_value ary)
|
||||
rand_state *random;
|
||||
|
||||
if (RARRAY_LEN(ary) > 1) {
|
||||
struct RClass *c = mrb_class_get_id(mrb, MRB_SYM(Random));
|
||||
struct RClass *c = mrb_class_get_id(mrb, ID_RANDOM_STRICT);
|
||||
if (mrb_get_args(mrb, "|I", &random, c) == 0) {
|
||||
random = random_default_state(mrb);
|
||||
}
|
||||
@@ -305,7 +306,7 @@ mrb_ary_sample(mrb_state *mrb, mrb_value ary)
|
||||
mrb_bool given;
|
||||
rand_state *random;
|
||||
mrb_int len;
|
||||
struct RClass *c = mrb_class_get_id(mrb, MRB_SYM(Random));
|
||||
struct RClass *c = mrb_class_get_id(mrb, ID_RANDOM_STRICT);
|
||||
|
||||
if (mrb_get_args(mrb, "|i?I", &n, &given, &random, c) < 2) {
|
||||
random = random_default_state(mrb);
|
||||
@@ -386,6 +387,7 @@ void mrb_mruby_random_gem_init(mrb_state *mrb)
|
||||
mrb_define_method(mrb, mrb->kernel_module, "srand", random_f_srand, MRB_ARGS_OPT(1));
|
||||
|
||||
random = mrb_define_class(mrb, "Random", mrb->object_class);
|
||||
mrb_const_set(mrb, mrb_obj_value(mrb->object_class), ID_RANDOM_STRICT, mrb_obj_value(random)); // for mrb_get_args()
|
||||
MRB_SET_INSTANCE_TT(random, MRB_TT_ISTRUCT);
|
||||
mrb_define_class_method(mrb, random, "rand", random_f_rand, MRB_ARGS_OPT(1));
|
||||
mrb_define_class_method(mrb, random, "srand", random_f_srand, MRB_ARGS_OPT(1));
|
||||
|
||||
Reference in New Issue
Block a user