How to crash Ruby by not registering global C variable?

Hi list,

On page 284 of Pickaxe, 2nd edition there is a passage:

If you create a Ruby object from C and store it in a C global variable without exporting it to Ruby, you must at least tell the garbage collector about it, lest ye be reaped inadvertently.

static VALUE obj;
/* ... */
obj = rb_ary_new();
rb_global_variable(obj);

I would like to reproduce this issue, but don’t know how. As far as I
understand, if rb_global_variable(obj) is not called then once the GC
will try to free up garbage memory it will try to destroy obj. GC will
fail and something interesting should happen :slight_smile:

I tried to implement this bug. While writing this e-mail I started to
think that I misunderstood what Dave T. is stating and that I’m
going the wrong way. But here is my code, in case I’m doing something
right:

reg_global.c:

1 #include <ruby.h>
2
3 static VALUE str;
4
5 int
6 main(int argc, char *argv)
7 {
8 ruby_init();
9 ruby_init_loadpath();
10
11 /
Create a string variable end export it to ruby */
12 str = rb_str_new2(“FooBar”);
13 rb_define_variable("$value", &str);
14
15 rb_require(“reg_global.rb”);
16
17 ruby_finalize();
18 return 0;
19 }

reg_global.rb:

1 # this script should be called from embedded ruby interpreter
2
3 def wrapper
4 p “value: #{$value}, id: #{$value.object_id}”
5 ObjectSpace.define_finalizer($value, lambda { |id| p “Finalizing
#{id}” })
6 $value = nil
7 end
8
9 wrapper
10
11 ObjectSpace.garbage_collect

When I execute reg_global I see the following (nothing special):

“value: FooBar, id: 76750”
“Finalizing 76750”

I expected Ruby to crash after this line:

11 ObjectSpace.garbage_collect

Has anyone some hints on how to reproduce the bug described in paragraph
above ?

On 3/31/07, 13 [email protected] wrote:

Hi list,

On page 284 of Pickaxe, 2nd edition there is a passage:

If you create a Ruby object from C and store it in a C global variable without exporting it to Ruby, you must at least tell the garbage collector about it, lest ye be reaped inadvertently.

Your masochistic behavior scares me a little bit ;), but if I
understand your intention correctly, you don’t actually want to call
rb_define_variable like you do on line 13… I believe calling that
will cause Ruby to reference the string which is typically a good
thing, but in this case it’s whats causing you to fail to see the
fireworks that you seek.

Even if Ruby never references your string, and the garbage collector
does ‘reap you inadvertently’ you probably wouldn’t see the fireworks
until you happened to dereference the ‘str’ variable later in your C
program, and even then only if the memory in question had been filled
with something interesting in the mean time.

Thats the slippery nature of the descrivbd problem, when you do fall
victim to it it might be tough to debug, because all you’re going to
have is occasionally an ‘str’ variable filled with something
strange.

Hope that helps,
-Harold

Oh, I see! Your answer is what I was looking for. Thanks!

If someone is curious here is this cool piece of code:

1 #include <ruby.h>
2
3 static VALUE str;
4
5 int
6 main(int argc, char *argv)
7 {
8 ruby_init();
9 ruby_init_loadpath();
10
11 str = rb_str_new2(“FooBar”);
12 /rb_global_variable(&str);/ /
Uncomment this if you don’t
want SF /
13
14 rb_eval_string(“GC.start”);
15
16 /
Boom! Here comes Segmentation fault */
17 printf(“Value: %s\n”, StringValuePtr(str));
18
19 ruby_finalize();
20 return 0;
21 }


Martins