Is it possible to initialize Ruby from C++ more than once in the same process?

Viewed 116

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.

0 Answers
Related