Skip to content
Browse files

"ensure" block fixes for catching uncaught exceptions

  • Loading branch information...
1 parent d90b854 commit 7c13ece02f93744a2a30359324673e244f7157d2 @mark-moseley mark-moseley committed Oct 5, 2009
Showing with 295 additions and 163 deletions.
  1. +7 −4 Rakefile
  2. +186 −110 ext/ruby_debug/ruby_debug.c
  3. +15 −11 ext/ruby_debug/ruby_debug.h
  4. +2 −1 test/data/catch3.cmd
  5. +37 −0 test/data/catch3.right
  6. +1 −0 test/data/save.cmd
  7. +47 −37 test/pm-catch3.rb
View
11 Rakefile
@@ -15,6 +15,9 @@ RUBY_DEBUG_VERSION = open("ext/ruby_debug/ruby_debug.c") do |f|
f.grep(/^#define DEBUG_VERSION/).first[/"(.+)"/,1]
end
+RUBY_DEBUG_TEENY = ".0"
+RUBY_DEBUG_BASE_TEENY = ".0"
+
COMMON_FILES = FileList[
'AUTHORS',
'CHANGES',
@@ -106,13 +109,13 @@ base_spec = Gem::Specification.new do |spec|
spec.homepage = "http://rubyforge.org/projects/ruby-debug19/"
spec.summary = "Fast Ruby debugger - core component"
spec.description = <<-EOF
-ruby-debug is a fast implementation of the standard Ruby debugger debug.rb.
+ruby-debug-base19 is a fast implementation of the standard Ruby debugger debug.rb.
It is implemented by utilizing a new Ruby C API hook. The core component
provides support that front-ends can build on. It provides breakpoint
handling, bindings for stack frames among other things.
EOF
- spec.version = "0.12.0"
+ spec.version = RUBY_DEBUG_VERSION + RUBY_DEBUG_BASE_TEENY
spec.authors = ["Kent Sibilev", "Mark Moseley"]
spec.email = "mark@fast-software.com"
@@ -138,12 +141,12 @@ cli_spec = Gem::Specification.new do |spec|
spec.name = "ruby-debug19"
spec.homepage = "http://rubyforge.org/projects/ruby-debug19/"
- spec.summary = "Command line interface (CLI) for ruby-debug-base"
+ spec.summary = "Command line interface (CLI) for ruby-debug-base19"
spec.description = <<-EOF
A generic command line interface for ruby-debug.
EOF
- spec.version = "0.11.7"
+ spec.version = RUBY_DEBUG_VERSION + RUBY_DEBUG_TEENY
spec.authors = ["Kent Sibilev", "Mark Moseley"]
spec.email = "mark@fast-software.com"
View
296 ext/ruby_debug/ruby_debug.c
@@ -33,7 +33,7 @@ typedef struct {
static VALUE hook_off = Qtrue;
static VALUE tracing = Qfalse;
static VALUE locker = Qnil;
-static VALUE debug = Qfalse;
+static VALUE debug_flag = Qfalse;
static VALUE catchall = Qtrue;
static VALUE skip_next_exception= Qfalse;
@@ -45,8 +45,8 @@ VALUE rdebug_threads_tbl = Qnil; /* Context for each of the threads */
VALUE mDebugger; /* Ruby Debugger Module object */
static VALUE bin_opt_call_c_function;
-static VALUE bin_putnil;
-static VALUE bin_leave;
+static VALUE bin_getdynamic;
+static VALUE bin_throw;
static VALUE cThreadsTable;
static VALUE cContext;
static VALUE cDebugThread;
@@ -113,6 +113,13 @@ get_event_name(rb_event_flag_t event)
}
}
+static void
+debug_runtime_error(debug_context_t *debug_context, const char *err)
+{
+ if (debug_context != NULL) CTX_FL_SET(debug_context, CTX_FL_IGNORE);
+ rb_raise(rb_eRuntimeError, err);
+}
+
inline static void
reset_stepping_stop_points(debug_context_t *debug_context)
{
@@ -175,7 +182,7 @@ id2ref_unprotected(VALUE id)
static VALUE
id2ref_error()
{
- if(debug == Qtrue)
+ if(debug_flag == Qtrue)
rb_p(rb_errinfo());
return Qnil;
}
@@ -328,6 +335,97 @@ check_thread_contexts()
st_foreach(threads_table->tbl, threads_table_check_i, 0);
}
+static struct iseq_catch_table_entry *
+create_catch_table(debug_context_t *debug_context, unsigned long cont)
+{
+ struct iseq_catch_table_entry *catch_table = &debug_context->catch_table.tmp_catch_table;
+
+ GET_THREAD()->parse_in_eval++;
+ GET_THREAD()->mild_compile_error++;
+ /* compiling with option Qfalse (no options) prevents debug hook calls during this catch routine
+ */
+ catch_table->iseq = rb_iseq_compile_with_option(
+ rb_str_new_cstr(""), rb_str_new_cstr("(exception catcher)"), INT2FIX(1), Qfalse);
+ GET_THREAD()->mild_compile_error--;
+ GET_THREAD()->parse_in_eval--;
+
+ catch_table->type = CATCH_TYPE_RESCUE;
+ catch_table->start = 0;
+ catch_table->end = ULONG_MAX;
+ catch_table->cont = cont;
+ catch_table->sp = 0;
+
+ return(catch_table);
+}
+
+static rb_control_frame_t *
+FUNC_FASTCALL(do_jump)(rb_thread_t *th, rb_control_frame_t *cfp)
+{
+ VALUE context;
+ debug_context_t *debug_context;
+ rb_control_frame_t *jump_cfp;
+ VALUE *jump_pc;
+
+ thread_context_lookup(th->self, &context, &debug_context, 0);
+ if (debug_context == NULL)
+ debug_runtime_error(NULL, "Lost context in jump");
+ cfp->pc[-2] = debug_context->saved_jump_ins[0];
+ cfp->pc[-1] = debug_context->saved_jump_ins[1];
+
+ if ((debug_context->jump_pc < debug_context->jump_cfp->iseq->iseq_encoded) ||
+ (debug_context->jump_pc >= debug_context->jump_cfp->iseq->iseq_encoded + debug_context->jump_cfp->iseq->iseq_size))
+ debug_runtime_error(debug_context, "Invalid jump PC target");
+
+ jump_cfp = debug_context->jump_cfp;
+ jump_pc = debug_context->jump_pc;
+ debug_context->jump_pc = NULL;
+ debug_context->jump_cfp = NULL;
+ if (!CTX_FL_TEST(debug_context, CTX_FL_EXCEPTION_TEST))
+ {
+ debug_context->last_line = 0;
+ debug_context->last_file = NULL;
+ debug_context->stop_next = 1;
+ }
+
+ if (cfp < jump_cfp)
+ {
+ /* save all intermediate-frame catch tables
+ +1 for target frame
+ +1 for array terminator
+ */
+ int frames = jump_cfp - cfp + 2;
+ debug_context->old_iseq_catch = (iseq_catch_t*)malloc(frames * sizeof(iseq_catch_t));
+ MEMZERO(debug_context->old_iseq_catch, iseq_catch_t, frames);
+ frames = 0;
+ do
+ {
+ if (cfp->iseq != NULL)
+ {
+ debug_context->old_iseq_catch[frames].iseq = cfp->iseq;
+ debug_context->old_iseq_catch[frames].catch_table = cfp->iseq->catch_table;
+ debug_context->old_iseq_catch[frames].catch_table_size = cfp->iseq->catch_table_size;
+ cfp->iseq->catch_table = NULL;
+ cfp->iseq->catch_table_size = 0;
+
+ frames++;
+ }
+ cfp = RUBY_VM_PREVIOUS_CONTROL_FRAME(cfp);
+ } while (cfp <= jump_cfp);
+
+ jump_cfp->iseq->catch_table_size = 1;
+ jump_cfp->iseq->catch_table =
+ create_catch_table(debug_context, jump_pc - jump_cfp->iseq->iseq_encoded);
+ jump_cfp->iseq->catch_table->sp = -1;
+
+ JUMP_TAG(TAG_RAISE);
+ }
+ else if (cfp > jump_cfp)
+ debug_runtime_error(debug_context, "Invalid jump frame target");
+
+ cfp->pc = jump_pc;
+ return(cfp);
+}
+
static rb_control_frame_t *
FUNC_FASTCALL(do_catchall)(rb_thread_t *th, rb_control_frame_t *cfp)
{
@@ -337,17 +435,35 @@ FUNC_FASTCALL(do_catchall)(rb_thread_t *th, rb_control_frame_t *cfp)
thread_context_lookup(th->self, &context, &debug_context, 0);
if (debug_context == NULL)
- rb_raise(rb_eRuntimeError, "Lost context in catchall");
+ debug_runtime_error(NULL, "Lost context in catchall");
if (debug_context->saved_frames == NULL)
return(cfp); /* re-throw exception */
+ if (CTX_FL_TEST(debug_context, CTX_FL_RETHROW))
+ {
+ cfp->pc[-2] = debug_context->saved_jump_ins[0];
+ cfp->pc[-1] = debug_context->saved_jump_ins[1];
+ }
+ else
+ {
+ CTX_FL_SET(debug_context, CTX_FL_CATCHING);
+ CTX_FL_UNSET(debug_context, CTX_FL_EXCEPTION_TEST);
+ }
+
+ /* restore the call frame state */
+ ZFREE(debug_context->cfp);
+ debug_context->cfp_count = debug_context->saved_cfp_count;
+ debug_context->saved_cfp_count = 0;
+ size = sizeof(rb_control_frame_t*) * debug_context->cfp_count;
+ debug_context->cfp = (rb_control_frame_t**)malloc(size);
+ memcpy(debug_context->cfp, debug_context->saved_cfp, size);
+ ZFREE(debug_context->saved_cfp);
+
size = sizeof(rb_control_frame_t) *
((debug_context->cfp[debug_context->cfp_count-1] - debug_context->cfp[0]) + 1);
memcpy(debug_context->cfp[0], debug_context->saved_frames, size);
ZFREE(debug_context->saved_frames);
- CTX_FL_SET(debug_context, CTX_FL_CATCHING);
- CTX_FL_UNSET(debug_context, CTX_FL_IN_EXCEPTION);
th->cfp = debug_context->cfp[0];
th->cfp->pc = th->cfp->iseq->iseq_encoded + find_prev_line_start(th->cfp);
return(th->cfp);
@@ -485,13 +601,14 @@ debug_context_create(VALUE thread)
debug_context->top_cfp = NULL;
debug_context->catch_cfp = NULL;
debug_context->saved_frames = NULL;
+ debug_context->saved_cfp = NULL;
+ debug_context->saved_cfp_count = 0;
debug_context->cfp = NULL;
if(rb_obj_class(thread) == cDebugThread)
CTX_FL_SET(debug_context, CTX_FL_IGNORE);
return Data_Wrap_Struct(cContext, debug_context_mark, debug_context_free, debug_context);
}
-
static void
thread_context_lookup(VALUE thread, VALUE *context, debug_context_t **debug_context, int create)
{
@@ -666,29 +783,6 @@ call_at_line_check(VALUE self, debug_context_t *debug_context, VALUE breakpoint,
call_at_line(context, debug_context, rb_str_new2(file), INT2FIX(line));
}
-static struct iseq_catch_table_entry *
-create_catch_table(debug_context_t *debug_context, unsigned long cont)
-{
- struct iseq_catch_table_entry *catch_table = &debug_context->catch_table.tmp_catch_table;
-
- GET_THREAD()->parse_in_eval++;
- GET_THREAD()->mild_compile_error++;
- /* compiling with option Qfalse (no options) prevents debug hook calls during this catch routine
- */
- catch_table->iseq = rb_iseq_compile_with_option(
- rb_str_new_cstr(""), rb_str_new_cstr("(exception catcher)"), INT2FIX(1), Qfalse);
- GET_THREAD()->mild_compile_error--;
- GET_THREAD()->parse_in_eval--;
-
- catch_table->type = CATCH_TYPE_RESCUE;
- catch_table->start = 0;
- catch_table->end = ULONG_MAX;
- catch_table->cont = cont;
- catch_table->sp = 0;
-
- return(catch_table);
-}
-
static int
set_thread_event_flag_i(st_data_t key, st_data_t val, st_data_t flag)
{
@@ -735,7 +829,7 @@ FUNC_FASTCALL(do_catch)(rb_thread_t *th, rb_control_frame_t *cfp)
thread_context_lookup(th->self, &context, &debug_context, 0);
if (debug_context == NULL)
- rb_raise(rb_eRuntimeError, "Lost context in catch");
+ debug_runtime_error(NULL, "Lost context in catch");
cfp->pc[-2] = debug_context->saved_jump_ins[0];
cfp->pc[-1] = debug_context->saved_jump_ins[1];
@@ -837,6 +931,7 @@ save_frames(debug_context_t *debug_context)
if (debug_context->cfp_count == 0)
return;
+ /* save the entire call frame state */
for (size = 0; size < debug_context->cfp_count; size++)
{
rb_binding_t *bind;
@@ -847,6 +942,7 @@ save_frames(debug_context_t *debug_context)
debug_context->catch_table.mod_name = rb_obj_class(rb_errinfo());
debug_context->catch_table.errinfo = rb_errinfo();
+
debug_context->catch_cfp = GET_THREAD()->cfp;
ZFREE(debug_context->saved_frames);
@@ -855,7 +951,13 @@ save_frames(debug_context_t *debug_context)
debug_context->saved_frames = (rb_control_frame_t*)malloc(size);
memcpy(debug_context->saved_frames, debug_context->cfp[0], size);
- CTX_FL_SET(debug_context, CTX_FL_IN_EXCEPTION);
+ ZFREE(debug_context->saved_cfp);
+ size = sizeof(rb_control_frame_t*) * debug_context->cfp_count;
+ debug_context->saved_cfp = (rb_control_frame_t**)malloc(size);
+ memcpy(debug_context->saved_cfp, debug_context->cfp, size);
+ debug_context->saved_cfp_count = debug_context->cfp_count;
+
+ CTX_FL_SET(debug_context, CTX_FL_EXCEPTION_TEST);
}
static int
@@ -897,9 +999,12 @@ handle_raise_event(rb_thread_t *th, debug_context_t *debug_context)
int i;
ZFREE(debug_context->saved_frames);
- if (debug_context->cfp_count == 0) //||
+ if (CTX_FL_TEST(debug_context, CTX_FL_RETHROW))
+ {
+ CTX_FL_UNSET(debug_context, CTX_FL_RETHROW);
return(0);
- if (!try_thread_lock(th, debug_context))
+ }
+ if (debug_context->cfp_count == 0 || !try_thread_lock(th, debug_context))
return(0);
if (skip_next_exception == Qtrue)
@@ -938,7 +1043,7 @@ handle_raise_event(rb_thread_t *th, debug_context_t *debug_context)
if (hit_count != Qnil)
{
if (!catch_exception(debug_context, mod_name))
- rb_raise(rb_eRuntimeError, "Could not catch exception");
+ debug_runtime_error(debug_context, "Could not catch exception");
return(1);
}
}
@@ -987,10 +1092,47 @@ debug_event_hook(rb_event_flag_t event, VALUE data, VALUE self, ID mid, VALUE kl
if (iseq == NULL || th->cfp->pc == NULL)
return;
- if ((self == rb_mKernel || self == mDebugger || klass == cContext || klass == 0) &&
- iseq->defined_method_id == id_binding_n)
+ if (event == RUBY_EVENT_LINE && CTX_FL_TEST(debug_context, CTX_FL_EXCEPTION_TEST))
+ {
+ if (iseq->type == ISEQ_TYPE_ENSURE)
+ {
+ /* don't allow "ensure" blocks to execute yet: jump out of here by re-throwing exception */
+ VALUE *jump_pc =
+ iseq->iseq_encoded + iseq->iseq_size - insn_len(BIN(getdynamic)) - insn_len(BIN(throw));
+
+ if (jump_pc[0] != bin_getdynamic || jump_pc[insn_len(BIN(getdynamic))] != bin_throw)
+ debug_runtime_error(debug_context, "Unexpected instructions in ENSURE block");
+
+ debug_context->jump_cfp = th->cfp;
+ debug_context->jump_pc = jump_pc;
+ debug_context->saved_jump_ins[0] = th->cfp->pc[0];
+ debug_context->saved_jump_ins[1] = th->cfp->pc[1];
+ th->cfp->pc[0] = bin_opt_call_c_function;
+ th->cfp->pc[1] = (VALUE)do_jump;
+ CTX_FL_SET(debug_context, CTX_FL_ENSURE_SKIPPED);
+ return;
+ }
+ else if (iseq->type == ISEQ_TYPE_RESCUE)
+ {
+ CTX_FL_UNSET(debug_context, CTX_FL_EXCEPTION_TEST);
+ if (CTX_FL_TEST(debug_context, CTX_FL_ENSURE_SKIPPED))
+ {
+ /* exception was caught by the code; need to start the whole thing over */
+ debug_context->saved_jump_ins[0] = th->cfp->pc[0];
+ debug_context->saved_jump_ins[1] = th->cfp->pc[1];
+ th->cfp->pc[0] = bin_opt_call_c_function;
+ th->cfp->pc[1] = (VALUE)do_catchall;
+ CTX_FL_UNSET(debug_context, CTX_FL_ENSURE_SKIPPED);
+ CTX_FL_SET(debug_context, CTX_FL_RETHROW);
+ return;
+ }
+ }
+ }
+
+ if (iseq->defined_method_id == id_binding_n &&
+ (self == rb_mKernel || self == mDebugger || klass == cContext || klass == 0))
return;
- if ((klass == cContext || klass == 0) && iseq->defined_method_id == id_frame_binding)
+ if (iseq->defined_method_id == id_frame_binding && (klass == cContext || klass == 0))
return;
if (event == RUBY_EVENT_LINE || event == RUBY_EVENT_CALL)
@@ -1006,7 +1148,6 @@ debug_event_hook(rb_event_flag_t event, VALUE data, VALUE self, ID mid, VALUE kl
if (iseq->type != ISEQ_TYPE_RESCUE && iseq->type != ISEQ_TYPE_ENSURE)
{
- CTX_FL_UNSET(debug_context, CTX_FL_IN_EXCEPTION);
if (debug_context->start_cfp == NULL || th->cfp > debug_context->start_cfp)
create_exception_catchall(debug_context);
}
@@ -1040,7 +1181,7 @@ debug_event_hook(rb_event_flag_t event, VALUE data, VALUE self, ID mid, VALUE kl
goto cleanup;
debug_context->cur_cfp = th->cfp;
- if (iseq && iseq->type != ISEQ_TYPE_RESCUE && iseq->type != ISEQ_TYPE_ENSURE)
+ if (iseq->type != ISEQ_TYPE_RESCUE && iseq->type != ISEQ_TYPE_ENSURE)
set_cfp(debug_context);
/* There can be many event calls per line, but we only want
@@ -1397,14 +1538,14 @@ debug_set_tracing(VALUE self, VALUE value)
static VALUE
debug_debug(VALUE self)
{
- return debug;
+ return debug_flag;
}
/* :nodoc: */
static VALUE
debug_set_debug(VALUE self, VALUE value)
{
- debug = RTEST(value) ? Qtrue : Qfalse;
+ debug_flag = RTEST(value) ? Qtrue : Qfalse;
return value;
}
@@ -2155,71 +2296,6 @@ context_stop_reason(VALUE self)
return ID2SYM(rb_intern(sym_name));
}
-static rb_control_frame_t *
-FUNC_FASTCALL(do_jump)(rb_thread_t *th, rb_control_frame_t *cfp)
-{
- VALUE context;
- debug_context_t *debug_context;
- rb_control_frame_t *jump_cfp;
- VALUE *jump_pc;
-
- thread_context_lookup(th->self, &context, &debug_context, 0);
- if (debug_context == NULL)
- rb_raise(rb_eRuntimeError, "Lost context in jump");
- cfp->pc[-2] = debug_context->saved_jump_ins[0];
- cfp->pc[-1] = debug_context->saved_jump_ins[1];
-
- if ((debug_context->jump_pc < debug_context->jump_cfp->iseq->iseq_encoded) ||
- (debug_context->jump_pc >= debug_context->jump_cfp->iseq->iseq_encoded + debug_context->jump_cfp->iseq->iseq_size))
- rb_raise(rb_eRuntimeError, "Invalid jump PC target");
-
- jump_cfp = debug_context->jump_cfp;
- jump_pc = debug_context->jump_pc;
- debug_context->jump_pc = NULL;
- debug_context->jump_cfp = NULL;
- debug_context->last_line = 0;
- debug_context->last_file = NULL;
- debug_context->stop_next = 1;
-
- if (cfp < jump_cfp)
- {
- /* save all intermediate-frame catch tables
- +1 for target frame
- +1 for array terminator
- */
- int frames = jump_cfp - cfp + 2;
- debug_context->old_iseq_catch = (iseq_catch_t*)malloc(frames * sizeof(iseq_catch_t));
- MEMZERO(debug_context->old_iseq_catch, iseq_catch_t, frames);
- frames = 0;
- do
- {
- if (cfp->iseq != NULL)
- {
- debug_context->old_iseq_catch[frames].iseq = cfp->iseq;
- debug_context->old_iseq_catch[frames].catch_table = cfp->iseq->catch_table;
- debug_context->old_iseq_catch[frames].catch_table_size = cfp->iseq->catch_table_size;
- cfp->iseq->catch_table = NULL;
- cfp->iseq->catch_table_size = 0;
-
- frames++;
- }
- cfp = RUBY_VM_PREVIOUS_CONTROL_FRAME(cfp);
- } while (cfp <= jump_cfp);
-
- jump_cfp->iseq->catch_table_size = 1;
- jump_cfp->iseq->catch_table =
- create_catch_table(debug_context, jump_pc - jump_cfp->iseq->iseq_encoded);
- jump_cfp->iseq->catch_table->sp = -1;
-
- JUMP_TAG(TAG_RAISE);
- }
- else if (cfp > jump_cfp)
- rb_raise(rb_eRuntimeError, "Invalid jump frame target");
-
- cfp->pc = jump_pc;
- return(cfp);
-}
-
/*
* call-seq:
* context.jump(line, file) -> bool
@@ -2410,8 +2486,8 @@ void
Init_ruby_debug()
{
TRANSLATE_INSNS(opt_call_c_function);
- TRANSLATE_INSNS(putnil);
- TRANSLATE_INSNS(leave);
+ TRANSLATE_INSNS(getdynamic);
+ TRANSLATE_INSNS(throw);
mDebugger = rb_define_module("Debugger");
rb_define_const(mDebugger, "VERSION", rb_str_new2(DEBUG_VERSION));
View
26 ext/ruby_debug/ruby_debug.h
@@ -3,17 +3,19 @@ enum ctx_stop_reason {CTX_STOP_NONE, CTX_STOP_STEP, CTX_STOP_BREAKPOINT,
CTX_STOP_CATCHPOINT};
/* Context flags */
-#define CTX_FL_SUSPEND (1<<1)
-#define CTX_FL_TRACING (1<<2)
-#define CTX_FL_SKIPPED (1<<3)
-#define CTX_FL_IGNORE (1<<4)
-#define CTX_FL_DEAD (1<<5)
-#define CTX_FL_WAS_RUNNING (1<<6)
-#define CTX_FL_ENABLE_BKPT (1<<7)
-#define CTX_FL_STEPPED (1<<8)
-#define CTX_FL_FORCE_MOVE (1<<9)
-#define CTX_FL_CATCHING (1<<10)
-#define CTX_FL_IN_EXCEPTION (1<<11)
+#define CTX_FL_SUSPEND (1<<1)
+#define CTX_FL_TRACING (1<<2)
+#define CTX_FL_SKIPPED (1<<3)
+#define CTX_FL_IGNORE (1<<4)
+#define CTX_FL_DEAD (1<<5)
+#define CTX_FL_WAS_RUNNING (1<<6)
+#define CTX_FL_ENABLE_BKPT (1<<7)
+#define CTX_FL_STEPPED (1<<8)
+#define CTX_FL_FORCE_MOVE (1<<9)
+#define CTX_FL_CATCHING (1<<10)
+#define CTX_FL_EXCEPTION_TEST (1<<11)
+#define CTX_FL_ENSURE_SKIPPED (1<<12)
+#define CTX_FL_RETHROW (1<<13)
#define CTX_FL_TEST(c,f) ((c)->flags & (f))
#define CTX_FL_SET(c,f) do { (c)->flags |= (f); } while (0)
@@ -59,6 +61,8 @@ typedef struct {
rb_control_frame_t *top_cfp;
rb_control_frame_t *catch_cfp;
rb_control_frame_t *saved_frames;
+ rb_control_frame_t **saved_cfp;
+ int saved_cfp_count;
//
struct RData catch_rdata;
struct rb_iseq_struct catch_iseq;
View
3 test/data/catch3.cmd
@@ -6,5 +6,6 @@ set autoeval off
set basename on
c
w
-jump +1
+p $var
+jump +4
c
View
37 test/data/catch3.right
@@ -0,0 +1,37 @@
+pm-catch3.rb:3
+def get_exception(arg)
+# # ***************************************************
+# # Test catch
+# # ***************************************************
+# set debuggertesting on
+Currently testing the debugger is on.
+# set autoeval off
+autoeval is off.
+# set basename on
+basename is on.
+# c
+divide by zero
+start1:foo begin:bar begin:foo ensure:zero_div rescue:
+Catchpoint at pm-catch3.rb:15: `divided by 0' (ZeroDivisionError)
+ from tdebug.rb:61:in `debug_program'
+ from tdebug.rb:247:in `<top (required)>'
+ from ../rdbg.rb:23:in `load'
+ from ../rdbg.rb:23:in `runner'
+ from ../rdbg.rb:32:in `<main>'
+pm-catch3.rb:15
+1/0 if arg
+# w
+--> #0 Object.bar(arg#Fixnum) at line pm-catch3.rb:15
+ #1 at line pm-catch3.rb:34
+ #2 Object.foo(arg#Fixnum) at line pm-catch3.rb:24
+ #3 Object.zero_div(arg#Fixnum) at line pm-catch3.rb:34
+ #4 at line pm-catch3.rb:45
+# p $var
+"start2:foo begin:bar begin:"
+# jump +4
+pm-catch3.rb:19
+$var = $var + "bar end:"
+# c
+7
+start2:foo begin:bar begin:bar end:foo end:foo ensure:
+done
View
1 test/data/save.cmd
@@ -31,3 +31,4 @@ source temp
##info break
##info catch
##show listsize
+c
View
84 test/pm-catch3.rb 100755 → 100644
@@ -1,37 +1,47 @@
-#!/usr/bin/env ruby
-# Test Debugger.catchpoint
-def get_exception
- LoadError
-end
-
-def bar(arg)
- $var = $var + "bar:"
- puts "bar begin"
- 1/0 if arg
- puts "bar end"
- if false
- raise LoadError
- end
-end
-
-def foo
- puts "foo begin"
- yield 1
- puts "foo end"
-rescue get_exception, NameError
- $var = $var + "rescue:"
- puts "get_exception rescue"
-ensure
- $var = $var + "ensure:"
-end
-
-def zero_div(arg)
- x = 5
- foo { |i| bar(i) }
- x + arg
-end
-
-$var = "start:"
-puts zero_div(10)
-puts $var
-puts "done"
+#!/usr/bin/env ruby
+# Test catching uncaught exceptions
+def get_exception(arg)
+ result = case arg
+ when 0 then LoadError
+ when 1 then ZeroDivisionError
+ when 2 then NoMethodError
+ else RuntimeError
+ end
+ return result
+end
+
+def bar(arg)
+ $var = $var + "bar begin:"
+ 1/0 if arg
+ if false
+ raise LoadError
+ end
+ $var = $var + "bar end:"
+end
+
+def foo(arg)
+ $var = $var + "foo begin:"
+ yield arg
+ $var = $var + "foo end:"
+rescue get_exception(0), NameError
+ $var = $var + "foo rescue:"
+ensure
+ $var = $var + "foo ensure:"
+end
+
+def zero_div(arg)
+ x = 5
+ foo(arg) { |i| bar(i) }
+ x + arg
+rescue get_exception(arg)
+ $var = $var + "zero_div rescue:"
+ return "divide by zero"
+end
+
+$var = "start1:"
+puts zero_div(1)
+puts $var
+$var = "start2:"
+puts zero_div(2)
+puts $var
+puts "done"

0 comments on commit 7c13ece

Please sign in to comment.
Something went wrong with that request. Please try again.