Need help understanding exceptions handling from C extension

I’m working on the test cases for my AIO extension library on windows
and I have been running into this error consistently on one of my

ArgumentError: NULL pointer given
tc_client.rb:129:in to_s' tc_client.rb:129:intest_addr_lookup_name_async’

The offending line is in the rescue block:

        q =
        a =
        c =
        n = 0

        assert(a.is_attached?, "should be attached")
        a.lookup("", c, :lookup_complete)

        5.times { n += q.process(100) }

        assert(c.lookups == 1, "didn't receive lookup callback")
        assert(n == 1, "not enough contexts processed")
    rescue Exception => ex
        puts "caught #{ex}"

The exception is raised from q.process which hooks directly to a C
functions and makes another function call to an internal API I
defined. In this code I have my async context handler:

      case CTX_ADDR_LOOKUP:


I believe this is ‘raising’ an exception. I see in other extensions
the usage of rb_protect() etc. I am under the impression that setjmp,
longjmp is being used to simulate exceptions in ruby, of which I’m
unfortunately not an expert in the usage.

I would like to be able to call out to ruby code without losing my
instruction pointer so that I may deliver the error to a registered
async error facility.

If someone could smack me over the head with a clue-by-four right now
that would be most appreciated :wink:

Of course I will continue learning and experimenting but I thouht this
would be a good time to solicit the knowledge of ruby-talk.

I caught the exception using rb_protect() but there is still a problem:

rbaio.c(1279): ruby error: NoMethodError: ???
rbaio.c(1292): from tc_client.rb:125:in process' rbaio.c(1292): from tc_client.rb:125:intest_addr_lookup_name_async’

The class name I can interpret okay but when I take $! and call the
to_s method on it I get another exception because of the NULL issue. I
don’t yet know why that is the case.

lasterr = rb_gv_get("$!");

// class and message
klass = rb_class_path(CLASS_OF(lasterr));
//message = rb_obj_as_string(lasterr);
DBG2("ruby error: %s: %s", RSTRING(klass)->ptr,


Uncommenting the conversion to string results in the NULL error.