summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ChangeLog18
-rw-r--r--eval.c4
-rw-r--r--test/ruby/test_settracefunc.rb51
-rw-r--r--vm.c17
-rw-r--r--vm_core.h1
-rw-r--r--vm_eval.c13
6 files changed, 90 insertions, 14 deletions
diff --git a/ChangeLog b/ChangeLog
index f5f9bc932a..34728a7301 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,21 @@
+Thu Jun 19 21:41:30 2014 Koichi Sasada <ko1@atdot.net>
+
+ * vm.c (rb_vm_rewind_cfp): add new function to rewind specified cfp
+ with invoking RUBY_EVENT_C_RETURN.
+ [Bug #9961]
+
+ * vm_core.h: ditto.
+
+ * eval.c (rb_protect): use it.
+
+ * eval.c (rb_rescue2): ditto.
+
+ * vm_eval.c (rb_iterate): ditto.
+
+ * test/ruby/test_settracefunc.rb: add a test.
+
+ * vm_core.h (rb_name_err_mesg_new):
+
Thu Jun 19 19:47:21 2014 Koichi Sasada <ko1@atdot.net>
* vm.c (invoke_block_from_c): move call/return event timing for
diff --git a/eval.c b/eval.c
index 7a8dce3d71..afad73c735 100644
--- a/eval.c
+++ b/eval.c
@@ -803,7 +803,7 @@ rb_rescue2(VALUE (* b_proc) (ANYARGS), VALUE data1,
}
}
else {
- th->cfp = cfp; /* restore */
+ rb_vm_rewind_cfp(th, cfp);
if (state == TAG_RAISE) {
int handle = FALSE;
@@ -862,7 +862,7 @@ rb_protect(VALUE (* proc) (VALUE), VALUE data, int * state)
SAVE_ROOT_JMPBUF(th, result = (*proc) (data));
}
else {
- th->cfp = cfp;
+ rb_vm_rewind_cfp(th, cfp);
}
MEMCPY(&(th)->root_jmpbuf, &org_jmpbuf, rb_jmpbuf_t, 1);
th->protect_tag = protect_tag.prev;
diff --git a/test/ruby/test_settracefunc.rb b/test/ruby/test_settracefunc.rb
index 0c8d7399cc..5d46fc3b08 100644
--- a/test/ruby/test_settracefunc.rb
+++ b/test/ruby/test_settracefunc.rb
@@ -1257,4 +1257,55 @@ class TestSetTraceFunc < Test::Unit::TestCase
assert_equal [], events # should be empty.
end
+
+ def test_rb_rescue
+ events = []
+ curr_thread = Thread.current
+ TracePoint.new(:a_call, :a_return){|tp|
+ next if curr_thread != Thread.current
+ events << [tp.event, tp.method_id]
+ }.enable do
+ begin
+ -Numeric.new
+ rescue => e
+ # ignore
+ end
+ end
+
+ assert_equal [
+ [:b_call, :test_rb_rescue],
+ [:c_call, :new],
+ [:c_call, :initialize],
+ [:c_return, :initialize],
+ [:c_return, :new],
+ [:c_call, :-@],
+ [:c_call, :coerce],
+ [:c_call, :to_s],
+ [:c_return, :to_s],
+ [:c_call, :new],
+ [:c_call, :initialize],
+ [:c_return, :initialize],
+ [:c_return, :new],
+ [:c_call, :exception],
+ [:c_return, :exception],
+ [:c_call, :backtrace],
+ [:c_return, :backtrace],
+ [:c_return, :coerce], # don't miss it!
+ [:c_call, :to_s],
+ [:c_return, :to_s],
+ [:c_call, :to_s],
+ [:c_return, :to_s],
+ [:c_call, :new],
+ [:c_call, :initialize],
+ [:c_return, :initialize],
+ [:c_return, :new],
+ [:c_call, :exception],
+ [:c_return, :exception],
+ [:c_call, :backtrace],
+ [:c_return, :backtrace],
+ [:c_return, :-@],
+ [:c_call, :===],
+ [:c_return, :===],
+ [:b_return, :test_rb_rescue]], events
+ end
end
diff --git a/vm.c b/vm.c
index bf7cb20af9..8eb02f3d84 100644
--- a/vm.c
+++ b/vm.c
@@ -288,6 +288,23 @@ rb_vm_pop_cfunc_frame(void)
vm_pop_frame(th);
}
+void
+rb_vm_rewind_cfp(rb_thread_t *th, rb_control_frame_t *cfp)
+{
+ /* check skipped frame */
+ while (th->cfp != cfp) {
+#if VMDEBUG
+ printf("skipped frame: %s\n", vm_frametype_name(th->cfp));
+#endif
+ if (VM_FRAME_TYPE(th->cfp) != VM_FRAME_MAGIC_CFUNC) {
+ vm_pop_frame(th);
+ }
+ else { /* unlikely path */
+ rb_vm_pop_cfunc_frame();
+ }
+ }
+}
+
/* obsolete */
void
rb_frame_pop(void)
diff --git a/vm_core.h b/vm_core.h
index 5bd9f6c6d0..f5cc498d3b 100644
--- a/vm_core.h
+++ b/vm_core.h
@@ -901,6 +901,7 @@ VALUE rb_name_err_mesg_new(VALUE obj, VALUE mesg, VALUE recv, VALUE method);
void rb_vm_stack_to_heap(rb_thread_t *th);
void ruby_thread_init_stack(rb_thread_t *th);
int rb_vm_control_frame_id_and_class(const rb_control_frame_t *cfp, ID *idp, VALUE *klassp);
+void rb_vm_rewind_cfp(rb_thread_t *th, rb_control_frame_t *cfp);
void rb_gc_mark_machine_stack(rb_thread_t *th);
diff --git a/vm_eval.c b/vm_eval.c
index 4ae9a1777a..5d05952bcf 100644
--- a/vm_eval.c
+++ b/vm_eval.c
@@ -1093,18 +1093,7 @@ rb_iterate(VALUE (* it_proc) (VALUE), VALUE data1,
th->errinfo = Qnil;
retval = GET_THROWOBJ_VAL(err);
- /* check skipped frame */
- while (th->cfp != cfp) {
-#if VMDEBUG
- printf("skipped frame: %s\n", vm_frametype_name(th->cfp));
-#endif
- if (VM_FRAME_TYPE(th->cfp) != VM_FRAME_MAGIC_CFUNC) {
- vm_pop_frame(th);
- }
- else { /* unlikely path */
- rb_vm_pop_cfunc_frame();
- }
- }
+ rb_vm_rewind_cfp(th, cfp);
}
else{
/* SDR(); printf("%p, %p\n", cdfp, escape_dfp); */