Bug #17643
closedRuby 3 embedded - no GC methods?
Description
The following code works on Ruby 2.x, but not on Ruby 3.0.0.
// Initialize Ruby VM
int argc = 0;
char* argv = (char*)malloc(1);
argv[0] = 0;
char** pArgv = &argv;
ruby_sysinit(&argc, &pArgv);
ruby_init();
ruby_init_loadpath();
// Try to call GC.start
int state;
VALUE result = rb_eval_string_protect("GC.start", &state);
VALUE err = rb_errinfo();
VALUE rubyMessage = rb_funcall(err, rb_intern("message"), 0);
char* message = RSTRING_PTR(rubyMessage);
message is "undefined method `start' for GC:Module"
This is true for all the GC methods (stop, stress, etc). Note if you create a Ruby script that contains GC.start and run it using the Ruby interpreter all is well.
Is there some new special way Ruby 3 needs to be embedded?
Note I tested this on mingw, MSVC and gcc (Fedora). All the same. Like I said above, this code works fine on Ruby 2.7 and earlier.
Files
Updated by jeremyevans0 (Jeremy Evans) over 3 years ago
- Status changed from Open to Assigned
- Assignee set to nobu (Nobuyoshi Nakada)
I've confirmed this behavior, and bisected it to 2c3c6c96cfc31eb387c643990375e6e1d67b409d. Looks like it could be fixed by calling rb_call_builtin_inits()
, but that doesn't appear to be exported. @nobu (Nobuyoshi Nakada) is that correct and is this expected? Should rb_call_builtin_inits()
be exported, or should another function be called?
Updated by cfis (Charlie Savage) over 3 years ago
Thanks for tracking this down Jeremy!
This would be very helpful to have back. I'm modernizing Rice (https://github.com/cfis/rice/tree/dev) and being able to call GC.start from Ruby code (versus rb_gc_start) as well as setting GC.stress are quite handy for verifying mark/free are being handled correctly.
Updated by cfis (Charlie Savage) over 3 years ago
Just following up. nobu any thoughts? I don't see any way of working around this currently when embedding Ruby.
Updated by nobu (Nobuyoshi Nakada) over 3 years ago
- Status changed from Assigned to Rejected
You don't call ruby_options
.
And the argv
made in this part is wrong.
int argc = 0; char* argv = (char*)malloc(1); argv[0] = 0; char** pArgv = &argv;
Updated by cfis (Charlie Savage) over 3 years ago
@nobu (Nobuyoshi Nakada) - Sorry that I missed your feedback.
I updated the code to call ruby_options, but that just hangs the interpreter. It thinks it is going to run a ruby script, but that is not correct. I have attached a screenshot of the call stack.
What I want to do is initialize the interpreter so I can later run code in it. As part of the initialization I'd like to set GC.stress to true.
I updated the embedding code to look like this (copied from Ruby's main function):
int argc = 0;
char* argv = nullptr;
char** pArgv = &argv;
ruby_sysinit(&argc, &pArgv);
{
RUBY_INIT_STACK;
ruby_init();
ruby_run_node(ruby_options(argc, pArgv));
}
initialized__ = true; // <----- this is never called
That doesn't work. Could you point me in the direction of what does work? Thanks!
Updated by cfis (Charlie Savage) over 3 years ago
Updated by cfis (Charlie Savage) over 3 years ago
Updated by cfis (Charlie Savage) over 3 years ago
Screenshot
Updated by nobu (Nobuyoshi Nakada) about 3 years ago
No arguments means reading the script from stdin.
You need to give a script name or an -e
option.
Updated by cfis (Charlie Savage) about 3 years ago
I don't want to do either of those things. Instead I would like to embed Ruby into a C++ program and then use it run tests.
Specifically, this is for Rice. The embed Ruby code:
https://github.com/jasonroelofs/rice/blob/master/test/embed_ruby.cpp
Then tests, for example:
https://github.com/jasonroelofs/rice/blob/master/test/test_Array.cpp
The reason I'd like to have access to the GC methods is to enable GC stress. That helps verify that Rice is correctly correctly managing memory when integrating with the interpreter.
This used to work fine in Ruby 2.x but not 3.x. I believe this is a regression and should be fixed.