I'm writing some unit tests. For that I try to initialize the Ruby interpreter and run code that uses it multiple times in a row. The first time it works fine, but on the second run, a crash in Ruby code occurs. It has been hard to nail the issue top-down so far, so I have tried to reproduce it bottom-up. Starting from this minimal example, taken right from the Running Ruby in C documentation.
Is it at all possible to initialize a Ruby interpreter multiple times in the same process? (Am I doing it wrong?)
Example Code
#include <ruby.h>
#include <iostream>
int rbCycle(int argc, char* argv[])
{
std::cout << "init" << std::endl;
ruby_init();
// char* options[] = { "-v", "-eputs 'Hello, world!'" };
// void* node = ruby_options(2, options);
// int state;
// if (ruby_executable_node(node, &state))
// {
// state = ruby_exec_node(node);
// }
// if ( state ) {
// std::cout << "error";
// }
std::cout << "cleanup" << std::endl;
return ruby_cleanup(0);
}
int main(int argc, char* argv[])
{
rbCycle(argc, argv);
rbCycle(argc, argv);
}
My compilation command line:
clang++ -g -O0 -o rb -I/System/Library/Frameworks/Ruby.framework/Versions/2.0/Headers -lruby ruby.cpp
Observations
Running the ruby_init(), ruby_cleanup(0) cycle two times triggers a crash on the second cleanup call. However, with the commented code enabled, it already crashes on the ruby_options call on the second cycle.
Output and stack trace with only init and cleanup:
init
cleanup
init
cleanup
* thread #1, queue = 'com.apple.main-thread', stop reason = EXC_BAD_ACCESS (code=1, address=0x120)
* frame #0: 0x00007fffc549838c libsystem_pthread.dylib`pthread_mutex_lock
frame #1: 0x00000001001b4c59 libruby.2.0.0.dylib`___lldb_unnamed_symbol2793$$libruby.2.0.0.dylib + 9
frame #2: 0x00000001001b1722 libruby.2.0.0.dylib`___lldb_unnamed_symbol2766$$libruby.2.0.0.dylib + 31
frame #3: 0x00000001000bf116 libruby.2.0.0.dylib`ruby_cleanup + 55
frame #4: 0x0000000100000f3b rb`rbCycle(argc=1, argv=0x00007fff5fbffa30) at ruby.cpp:22
frame #5: 0x00000001000010da rb`main(argc=1, argv=0x00007fff5fbffa30) at ruby.cpp:28
frame #6: 0x00007fffc5281235 libdyld.dylib`start + 1
Output and stack trace with the commented code enabled:
init
Hello, world!
cleanup
init
* thread #1, queue = 'com.apple.main-thread', stop reason = EXC_BAD_ACCESS (code=1, address=0x180)
* frame #0: 0x00000001000befb4 libruby.2.0.0.dylib`ruby_options + 65
frame #1: 0x0000000100000e3c rb`rbCycle(argc=1, argv=0x00007fff5fbffa30) at ruby.cpp:10
frame #2: 0x000000010000107a rb`main(argc=1, argv=0x00007fff5fbffa30) at ruby.cpp:28
frame #3: 0x00007fffc5281235 libdyld.dylib`start + 1
This is ruby 2.0.0p648 (2015-12-16 revision 53162) [universal.x86_64-darwin16] on macOS 10.12.5.