Search code examples
crubyruby-c-extension

Ruby C Api handling exceptions


I am running a ruby script through C as follows:

#include <ruby.h>

int main(void) {
  ruby_init();

  int status;
  rb_load_protect(rb_str_new2("./test.rb"), 0, &status);

  if (status) {
    VALUE rbError = rb_funcall(rb_gv_get("$!"), rb_intern("message"), 0);
    printf("%s\n", StringValueCStr(rbError));
  }

  ruby_finalize();
  return status;
}

The ruby script:

1.hello

When I run it now, I get this output:

undefined method `hello' for 1:Integer

This is as expected. I then define this method:

VALUE hello(VALUE self) {
  return Qnil;
}

// just after ruby_init()
rb_define_method(rb_cInteger, "hello", hello, 0);

When I run it now, I get

ruby: [BUG] Segmentation fault at 0x00000000000000b0
/* ... */

How can I handle the error here? $! is nil in this case but I don't know why.


Solution

  • I think you just need to initialise status:

    int status = 0;
    

    It looks like rb_load_protect sets status if there is an exception, but doesn’t set it to zero if there isn’t, but by passing &status to it you are suppressing any unitialised variable warnings from the compiler.

    What’s happening at the moment is status starts as some (non-zero) garbage, and doesn’t get set to zero if there is no exception, so the if block is always executed. However, if there isn’t an exception, then $! is nil, so calling message on it results in an unhandled exception which causes the crash.