Catching segmentation faults from Ruby

(Iain Dooley) #1

hello, i've got ruby embedded into an application, and i've built a code editor that allows you to edit ruby code for a GUI at runtime. only problem is that something like this:

@parent.child("widgetName").display(@count)

will crash ruby if there is no child of parent with name "widgetName". i know that there is rb_funcall_protect that allows you to trap errors, but the problem is that i'm not doing an rb_funcall. the functions are being called from with Qt/Ruby bindings. is there a way that i can trap all errors from the ruby interpreter to prevent segfaults in dynamically edited code from crashing the program?

cheers

iain

(ts) #2

will crash ruby if there is no child of parent with name "widgetName". i
know that there is rb_funcall_protect that allows you to trap errors,
but the problem is that i'm not doing an rb_funcall. the functions are
being called from with Qt/Ruby bindings. is there a way that i can trap
all errors from the ruby interpreter to prevent segfaults in dynamically
edited code from crashing the program?

Look at rb_eval_string_protect(), rb_protect()

Guy Decoux

(Iain Dooley) #3

ts wrote:

"I" == Iain Dooley <idoo4002@mail.usyd.edu.au> writes:

> will crash ruby if there is no child of parent with name "widgetName". i > know that there is rb_funcall_protect that allows you to trap errors, > but the problem is that i'm not doing an rb_funcall. the functions are > being called from with Qt/Ruby bindings. is there a way that i can trap > all errors from the ruby interpreter to prevent segfaults in dynamically > edited code from crashing the program?

Look at rb_eval_string_protect(), rb_protect()

in fact, the problem here is that i'm not calling the functions from within my code. what i do is create a new Qt::Object class using rb_funcall, then i look within Qt/Ruby bindings to find the underlying QObject (C++ object), then bind the slots present in this object to a dynamically loaded .ui interface file using QWidgetFactory::create().

this returns a class of object QWidget. i then create a new Qt::Widget class using rb_funcall, find the underlying object and switch the pointer to the object returned by QWidgetFactory::create(). This means that you can create .ui file in Qt Designer and then load it into an application runner and write the code that controls the GUI behaviour at runtime.

it works beautifully, but because i am not doing an eval_string or a funcall to execute the code (it is all handled within Smoke and Qt/Ruby) i can't simply put rb_protect() around it. my main routine looks like this:

#include <qapplication.h>
#include "runner.h"
#include <ruby.h>

int main( int argc, char *argv[] )
{
     QApplication app( argc, argv );
     ruby_init();
     Runner *runner = new Runner();
     app.setMainWidget( runner );
     runner->show();
     return app.exec();
}

would it be possible, do you think to have:

#include <qapplication.h>
#include "runner.h"
#include <ruby.h>

int main( int argc, char *argv[] )
{
     int ret = 2;

     QApplication app( argc, argv );
     ruby_init();
     Runner *runner = new Runner();
     app.setMainWidget( runner );
     runner->show();

     while(ret==2)
         ret = executeProgram(app);

     return ret;
}

int executeProgram(QApplication &app)
{
     int ret = 0;

     try
     {
         ret = app.exec();
     }

     catch(RubyException *exc)
     {
         //DISPLAY SOME ERROR MESSAGE OR MODAL DIALOG
         ret = 2;
     }

     return ret;
}

does such a RubyException exists? is there some general exception that will come floating up unhandled out of my application to meet me?

cheers

ian

(ts) #4

     try
     catch(RubyException *exc)

Your try/catch is rb_protect()

Guy Decoux

(Iain Dooley) #5

ts wrote:

"I" == Iain Dooley <idoo4002@mail.usyd.edu.au> writes:

> try
> catch(RubyException *exc)

Your try/catch is rb_protect()

but surely i can't call:

rb_protect(app.exec(),VALUE ?,RESULT ?);

??

(ts) #6

but surely i can't call:

rb_protect(app.exec(),VALUE ?,RESULT ?);

  /* Something like this */

  static VALUE
  call_exec_for_app(QApplication *app)
  {
      return app->exec();
  }

  /* ... */
  int status;
  VALUE res;
  /* ... */
  
  res = rb_protect(call_exec_for_app, (VALUE)&app, &status);
  if (status) {
     /* there is a ruby error */
  }
  /* ... */

Guy Decoux

(Iain Dooley) #7

ts wrote:

"I" == Iain Dooley <idoo4002@mail.usyd.edu.au> writes:

> but surely i can't call:

> rb_protect(app.exec(),VALUE ?,RESULT ?);

  /* Something like this */

  static VALUE
  call_exec_for_app(QApplication *app)
  {
      return app->exec();
  }

  /* ... */
  int status;
  VALUE res;
  /* ... */
    res = rb_protect(call_exec_for_app, (VALUE)&app, &status);
  if (status) {
     /* there is a ruby error */
  }
  /* ... */

excellent!! i thought that rb_protect was only for ruby methods.

i'll try that out. thanks very much

iain

(Iain Dooley) #8

ts wrote:

"I" == Iain Dooley <idoo4002@mail.usyd.edu.au> writes:

> but surely i can't call:

> rb_protect(app.exec(),VALUE ?,RESULT ?);

  /* Something like this */

  static VALUE
  call_exec_for_app(QApplication *app)
  {
      return app->exec();
  }

  /* ... */
  int status;
  VALUE res;
  /* ... */
    res = rb_protect(call_exec_for_app, (VALUE)&app, &status);
  if (status) {
     /* there is a ruby error */
  }
  /* ... */

it appears that i can't pass the name of a C function to rb_protect. i've tried these things:

/*** DEFINITION OF MY EXECUTE FUNCTION***/

VALUE executeApplication(void);

VALUE executeApplication()
{
     return app->exec();
}

1) passing the C function to rb_protect as follows:

         VALUE res = rb_protect(executeApplication, (VALUE)0, &status);

gives the following compile errors:

main.cpp:30: error: invalid conversion from `VALUE (*)()' to `VALUE (*)(VALUE)'
main.cpp:30: error: initializing argument 1 of `VALUE rb_protect(VALUE (*)(VALUE), VALUE, int*)'

2) using rb_define_method to define the method in ruby and then using rb_const_get to get it out and then calling it:

     rb_define_method(rb_cObject,"executeApplication",executeApplication,0);

VALUE res;
VALUE func = rb_const_get(rb_cObject,rb_intern("executeApplication"));
res = rb_protect(func, (VALUE)0, &status);

gives the following compile errors:

main.cpp:24: error: invalid conversion from `VALUE (*)()' to `VALUE (*)(...)'
main.cpp:24: error: initializing argument 3 of `void rb_define_method(VALUE, const char*, VALUE (*)(...), int)'
main.cpp:30: error: invalid conversion from `VALUE' to `VALUE (*)(VALUE)'
main.cpp:30: error: initializing argument 1 of `VALUE rb_protect(VALUE (*)(VALUE), VALUE, int*)'

these types really confuse the hell out of me. what is VALUE(*)() ?!?! VALUE everywhere... this is the last tiny little thing that i have to do for the summer of code ends in two days ... just need to protect the calls!

cheers

iain

(ts) #9

it appears that i can't pass the name of a C function to rb_protect.

use a typecast

Guy Decoux

(Iain Dooley) #10

ts wrote:

"I" == Iain Dooley <idoo4002@mail.usyd.edu.au> writes:

> it appears that i can't pass the name of a C function to rb_protect.

use a typecast

okay, so i was able to use:

rb_protect((VALUE (*)(VALUE))executeApplication,(VALUE)0,&status);

thanks very much for your advice.

however, we are back to the original problem, because what is actually happening is not a ruby exception, but is in fact a segmentation fault, caused by a line such as this:

@parent.child("nonexistentChildWidget").text

because this code is being edited at runtime, if the user mistypes the name of a child for example, then tests the code, i want an error to pop saying "there was an error in your code" or something. at the moment, it dies like this:

matt_test.rb:9: [BUG] Segmentation fault
ruby 1.8.2 (2004-12-25) [i386-freebsd5]

Abort (core dumped)

so i need a way to catch a segmentation fault, not ruby exceptions.

cheers

iain

(ts) #11

because this code is being edited at runtime, if the user mistypes the
name of a child for example, then tests the code, i want an error to pop
saying "there was an error in your code" or something. at the moment, it
dies like this:

matt_test.rb:9: [BUG] Segmentation fault
ruby 1.8.2 (2004-12-25) [i386-freebsd5]

Do it do the same thing when the script is called directly (outside the
embedded application) ?

If yes, it's a bug in this extension and it must be fixed.

Guy Decoux

(Iain Dooley) #12

ts wrote:

"I" == Iain Dooley <idoo4002@mail.usyd.edu.au> writes:

> because this code is being edited at runtime, if the user mistypes the > name of a child for example, then tests the code, i want an error to pop > saying "there was an error in your code" or something. at the moment, it > dies like this:

> matt_test.rb:9: [BUG] Segmentation fault
> ruby 1.8.2 (2004-12-25) [i386-freebsd5]

Do it do the same thing when the script is called directly (outside the
embedded application) ?

If yes, it's a bug in this extension and it must be fixed.

well, actually the script doesn't do anything outside the application!! it is just a class definition for receiving signals from a UI built in Qt Designer.

this is part of Qt/Ruby bindings, so obviously what's happening is that, because @parent.child("someName") returns nil, trying to access this is causing a segmentation fault. so @parent.child("someName").text is trying to call a function on an object that doesn't exist.

does that sound like it is a bug in Qt Ruby bindings?

cheers

iain

(ts) #13

this is part of Qt/Ruby bindings, so obviously what's happening is that,
because @parent.child("someName") returns nil, trying to access this is
causing a segmentation fault. so @parent.child("someName").text is
trying to call a function on an object that doesn't exist.

It must not segfault

moulon% ruby -e 'nil.text'
-e:1: undefined method `text' for nil:NilClass (NoMethodError)
moulon%

does that sound like it is a bug in Qt Ruby bindings?

try to reproduce it outside your embedded applications, if it segfault the
bug is in Qt ruby

Guy Decoux

(Iain Dooley) #14

ts wrote:

"I" == Iain Dooley <idoo4002@mail.usyd.edu.au> writes:

> this is part of Qt/Ruby bindings, so obviously what's happening is that, > because @parent.child("someName") returns nil, trying to access this is > causing a segmentation fault. so @parent.child("someName").text is > trying to call a function on an object that doesn't exist.

It must not segfault

moulon% ruby -e 'nil.text'
-e:1: undefined method `text' for nil:NilClass (NoMethodError)
moulon%

> does that sound like it is a bug in Qt Ruby bindings?

try to reproduce it outside your embedded applications, if it segfault the
bug is in Qt ruby

okay, thanks for your help.

iain