Fixed #26 (Exceptions are reported every time they propagate up in the call chain in the ruby debugger)

This commit is contained in:
Matthias Koefferlein 2017-12-02 23:02:45 +01:00
parent 1bb662b9ed
commit fdb012aa2d
5 changed files with 114 additions and 60 deletions

View File

@ -618,12 +618,51 @@ private:
}
};
// -------------------------------------------------------------------
// Ruby interpreter private data
struct RubyInterpreterPrivateData
{
RubyInterpreterPrivateData ()
{
saved_stderr = Qnil;
saved_stdout = Qnil;
stdout_klass = Qnil;
stderr_klass = Qnil;
current_console = 0;
current_exec_handler = 0;
current_exec_level = 0;
in_trace = false;
exit_on_next = false;
block_exceptions = false;
ignore_next_exception = false;
}
VALUE saved_stderr;
VALUE saved_stdout;
VALUE stdout_klass;
VALUE stderr_klass;
gsi::Console *current_console;
std::vector<gsi::Console *> consoles;
gsi::ExecutionHandler *current_exec_handler;
int current_exec_level;
bool in_trace;
bool exit_on_next;
bool block_exceptions;
bool ignore_next_exception;
std::string debugger_scope;
std::map<const char *, size_t> file_id_map;
std::vector<gsi::ExecutionHandler *> exec_handlers;
std::set<std::string> package_paths;
};
// -------------------------------------------------------------------
// Ruby API
#define RBA_TRY \
VALUE __error_msg = Qnil; \
int __estatus = 0; \
VALUE __exc = Qnil; \
VALUE __eclass = Qnil; \
{ \
try {
@ -636,6 +675,9 @@ private:
__estatus = ex.status (); \
__eclass = rb_eSystemExit; \
__error_msg = rb_str_new2 ((ex.msg () + tl::to_string (QObject::tr (" in ")) + (where)).c_str ()); \
} catch (rba::RubyError &ex) { \
__eclass = rb_eRuntimeError; \
__exc = ex.exc (); \
} catch (tl::Exception &ex) { \
__eclass = rb_eRuntimeError; \
__error_msg = rb_str_new2 ((ex.msg () + tl::to_string (QObject::tr (" in ")) + (where)).c_str ()); \
@ -644,7 +686,12 @@ private:
__error_msg = rb_str_new2 ((tl::to_string (QObject::tr ("Unspecific exception in ")) + (where)).c_str ()); \
} \
} \
if (__eclass == rb_eSystemExit) { \
if (__exc != Qnil) { \
/* Reraise the exception without blocking in the debugger */ \
/* TODO: should not access private data */ \
RubyInterpreter::instance ()->d->block_exceptions = true; \
rb_exc_raise (__exc); \
} else if (__eclass == rb_eSystemExit) { \
/* HINT: we do the rb_raise outside any destructor code - sometimes this longjmp seems not to work properly */ \
VALUE args [2]; \
args [0] = INT2NUM (__estatus); \
@ -1389,41 +1436,6 @@ stderr_winsize (VALUE self)
// --------------------------------------------------------------------------
// RubyInterpreter implementation
struct RubyInterpreterPrivateData
{
RubyInterpreterPrivateData ()
{
saved_stderr = Qnil;
saved_stdout = Qnil;
stdout_klass = Qnil;
stderr_klass = Qnil;
current_console = 0;
current_exec_handler = 0;
current_exec_level = 0;
in_trace = false;
exit_on_next = false;
block_exceptions = false;
ignore_next_exception = false;
}
VALUE saved_stderr;
VALUE saved_stdout;
VALUE stdout_klass;
VALUE stderr_klass;
gsi::Console *current_console;
std::vector<gsi::Console *> consoles;
gsi::ExecutionHandler *current_exec_handler;
int current_exec_level;
bool in_trace;
bool exit_on_next;
bool block_exceptions;
bool ignore_next_exception;
std::string debugger_scope;
std::map<const char *, size_t> file_id_map;
std::vector<gsi::ExecutionHandler *> exec_handlers;
std::set<std::string> package_paths;
};
static RubyInterpreter *sp_rba_interpreter = 0;
struct RubyConstDescriptor

View File

@ -32,26 +32,6 @@
namespace rba
{
/**
* @brief A class encapsulating a ruby exception
*/
class RBA_PUBLIC RubyError
: public tl::ScriptError
{
public:
RubyError (const char *msg, const char *cls, const std::vector <tl::BacktraceElement> &backtrace)
: tl::ScriptError (msg, cls, backtrace)
{ }
RubyError (const char *msg, const char *sourcefile, int line, const char *cls, const std::vector <tl::BacktraceElement> &backtrace)
: tl::ScriptError (msg, sourcefile, line, cls, backtrace)
{ }
RubyError (const RubyError &d)
: tl::ScriptError (d)
{ }
};
struct RubyInterpreterPrivateData;
/**

View File

@ -30,12 +30,41 @@
#include "gsiMethods.h"
#include "gsiSignals.h"
#include "tlObject.h"
#include "tlScriptError.h"
#include <ruby.h>
namespace rba
{
/**
* @brief A class encapsulating a ruby exception
*/
class RubyError
: public tl::ScriptError
{
public:
RubyError (VALUE exc, const char *msg, const char *cls, const std::vector <tl::BacktraceElement> &backtrace)
: tl::ScriptError (msg, cls, backtrace), m_exc (exc)
{ }
RubyError (VALUE exc, const char *msg, const char *sourcefile, int line, const char *cls, const std::vector <tl::BacktraceElement> &backtrace)
: tl::ScriptError (msg, sourcefile, line, cls, backtrace), m_exc (exc)
{ }
RubyError (const RubyError &d)
: tl::ScriptError (d), m_exc (d.m_exc)
{ }
VALUE exc () const
{
return m_exc;
}
private:
VALUE m_exc;
};
/**
* @brief The proxy object that represents the C++ object on the Ruby side
*/

View File

@ -25,6 +25,7 @@
#include "rba.h"
#include "rbaUtils.h"
#include "rbaInternal.h"
#if HAVE_RUBY_VERSION_CODE >= 20200
# include <ruby/debug.h>
@ -168,9 +169,9 @@ rba_check_error ()
}
if (info.line > 0) {
throw RubyError (emsg.c_str (), info.file.c_str (), info.line, eclass.c_str (), bt);
throw RubyError (lasterr, emsg.c_str (), info.file.c_str (), info.line, eclass.c_str (), bt);
} else {
throw RubyError (emsg.c_str (), eclass.c_str (), bt);
throw RubyError (lasterr, emsg.c_str (), eclass.c_str (), bt);
}
}

View File

@ -31,6 +31,12 @@ private
end
class MyException < RuntimeError
def initialize(s)
super(s)
end
end
class XEdge < RBA::Edge
def initialize
super(RBA::Point.new(1,2), RBA::Point.new(3,4))
@ -2601,4 +2607,30 @@ class Basic_TestClass < TestBase
end
def test_73
begin
poly = RBA::Polygon::new(RBA::Box::new(0, 0, 100, 100))
# passing exceptions over iterators is critical because it involves
# a Ruby/C++ and C++/Ruby transition
poly.each_edge do |e|
raise MyException::new("some exception")
end
rescue => ex
assert_equal(ex.class.to_s, "MyException")
assert_equal(ex.to_s, "some exception")
end
begin
raise MyException::new("another exception")
rescue => ex
assert_equal(ex.class.to_s, "MyException")
assert_equal(ex.to_s, "another exception")
end
end
end