[前][次][番号順一覧][スレッド一覧]

ruby-changes:34338

From: ko1 <ko1@a...>
Date: Fri, 13 Jun 2014 17:50:17 +0900 (JST)
Subject: [ruby-changes:34338] ko1:r46419 (trunk): * vm_trace.c: clear and restore recursive checking thread local data

ko1	2014-06-13 17:50:11 +0900 (Fri, 13 Jun 2014)

  New Revision: 46419

  http://svn.ruby-lang.org/cgi-bin/viewvc.cgi?view=revision&revision=46419

  Log:
    * vm_trace.c: clear and restore recursive checking thread local data
      to avoid unexpected throw from TracePoint.
      [Bug #9940]
    * test/ruby/test_settracefunc.rb: add a test.
    * thread.c: adde
      * rb_threadptr_reset_recursive_data(rb_thread_t *th);
      * rb_threadptr_restore_recursive_data(rb_thread_t *th, VALUE old);
    * vm_core.h: ditto.

  Modified files:
    trunk/ChangeLog
    trunk/test/ruby/test_settracefunc.rb
    trunk/thread.c
    trunk/vm_core.h
    trunk/vm_trace.c
Index: ChangeLog
===================================================================
--- ChangeLog	(revision 46418)
+++ ChangeLog	(revision 46419)
@@ -1,3 +1,17 @@ https://github.com/ruby/ruby/blob/trunk/ChangeLog#L1
+Fri Jun 13 17:46:31 2014  Koichi Sasada  <ko1@a...>
+
+	* vm_trace.c: clear and restore recursive checking thread local data
+	  to avoid unexpected throw from TracePoint.
+	  [Bug #9940]
+
+	* test/ruby/test_settracefunc.rb: add a test.
+
+	* thread.c: adde
+	  * rb_threadptr_reset_recursive_data(rb_thread_t *th);
+	  * rb_threadptr_restore_recursive_data(rb_thread_t *th, VALUE old);
+
+	* vm_core.h: ditto.
+
 Fri Jun 13 17:33:14 2014  Nobuyoshi Nakada  <nobu@r...>
 
 	* array.c (rb_ary_combination): iterate on a shared copy, and use
Index: vm_core.h
===================================================================
--- vm_core.h	(revision 46418)
+++ vm_core.h	(revision 46419)
@@ -1046,6 +1046,9 @@ void rb_threadptr_exec_event_hooks_and_p https://github.com/ruby/ruby/blob/trunk/vm_core.h#L1046
 #define EXEC_EVENT_HOOK_AND_POP_FRAME(th_, flag_, self_, id_, klass_, data_) \
   EXEC_EVENT_HOOK_ORIG(th_, flag_, self_, id_, klass_, data_, 1)
 
+VALUE rb_threadptr_reset_recursive_data(rb_thread_t *th);
+void rb_threadptr_restore_recursive_data(rb_thread_t *th, VALUE old);
+
 RUBY_SYMBOL_EXPORT_BEGIN
 
 int rb_thread_check_trap_pending(void);
Index: thread.c
===================================================================
--- thread.c	(revision 46418)
+++ thread.c	(revision 46419)
@@ -2738,22 +2738,25 @@ rb_thread_inspect(VALUE thread) https://github.com/ruby/ruby/blob/trunk/thread.c#L2738
     return str;
 }
 
-VALUE
-rb_thread_local_aref(VALUE thread, ID id)
+static VALUE
+threadptr_local_aref(rb_thread_t *th, ID id)
 {
-    rb_thread_t *th;
     st_data_t val;
 
-    GetThreadPtr(thread, th);
-    if (!th->local_storage) {
-	return Qnil;
-    }
-    if (st_lookup(th->local_storage, id, &val)) {
+    if (th->local_storage && st_lookup(th->local_storage, id, &val)) {
 	return (VALUE)val;
     }
     return Qnil;
 }
 
+VALUE
+rb_thread_local_aref(VALUE thread, ID id)
+{
+    rb_thread_t *th;
+    GetThreadPtr(thread, th);
+    return threadptr_local_aref(th, id);
+}
+
 /*
  *  call-seq:
  *      thr[sym]   -> obj or nil
@@ -2822,26 +2825,35 @@ rb_thread_aref(VALUE thread, VALUE key) https://github.com/ruby/ruby/blob/trunk/thread.c#L2825
     return rb_thread_local_aref(thread, id);
 }
 
-VALUE
-rb_thread_local_aset(VALUE thread, ID id, VALUE val)
+static VALUE
+threadptr_local_aset(rb_thread_t *th, ID id, VALUE val)
 {
-    rb_thread_t *th;
-    GetThreadPtr(thread, th);
-
-    if (OBJ_FROZEN(thread)) {
-	rb_error_frozen("thread locals");
-    }
     if (NIL_P(val)) {
 	if (!th->local_storage) return Qnil;
 	st_delete_wrap(th->local_storage, id);
 	return Qnil;
     }
+    else {
     if (!th->local_storage) {
 	th->local_storage = st_init_numtable();
     }
     st_insert(th->local_storage, id, val);
     return val;
 }
+}
+
+VALUE
+rb_thread_local_aset(VALUE thread, ID id, VALUE val)
+{
+    rb_thread_t *th;
+    GetThreadPtr(thread, th);
+
+    if (OBJ_FROZEN(thread)) {
+	rb_error_frozen("thread locals");
+    }
+
+    return threadptr_local_aset(th, id, val);
+}
 
 /*
  *  call-seq:
@@ -4674,6 +4686,20 @@ recursive_list_access(void) https://github.com/ruby/ruby/blob/trunk/thread.c#L4686
     return list;
 }
 
+VALUE
+rb_threadptr_reset_recursive_data(rb_thread_t *th)
+{
+    VALUE old = threadptr_local_aref(th, recursive_key);
+    threadptr_local_aset(th, recursive_key, Qnil);
+    return old;
+}
+
+void
+rb_threadptr_restore_recursive_data(rb_thread_t *th, VALUE old)
+{
+    threadptr_local_aset(th, recursive_key, old);
+}
+
 /*
  * Returns Qtrue iff obj_id (or the pair <obj, paired_obj>) is already
  * in the recursion list.
Index: vm_trace.c
===================================================================
--- vm_trace.c	(revision 46418)
+++ vm_trace.c	(revision 46419)
@@ -331,6 +331,7 @@ rb_threadptr_exec_event_hooks_orig(rb_tr https://github.com/ruby/ruby/blob/trunk/vm_trace.c#L331
 	    trace_arg->self != rb_mRubyVMFrozenCore /* skip special methods. TODO: remove it. */) {
 	    const VALUE errinfo = th->errinfo;
 	    const int outer_state = th->state;
+	    const VALUE old_recursive = rb_threadptr_reset_recursive_data(th);
 	    int state = 0;
 	    th->state = 0;
 	    th->errinfo = Qnil;
@@ -351,6 +352,7 @@ rb_threadptr_exec_event_hooks_orig(rb_tr https://github.com/ruby/ruby/blob/trunk/vm_trace.c#L352
 	  terminate:
 	    th->trace_arg = 0;
 	    th->vm->trace_running--;
+	    rb_threadptr_restore_recursive_data(th, old_recursive);
 
 	    if (state) {
 		if (pop_p) {
Index: test/ruby/test_settracefunc.rb
===================================================================
--- test/ruby/test_settracefunc.rb	(revision 46418)
+++ test/ruby/test_settracefunc.rb	(revision 46419)
@@ -1188,6 +1188,18 @@ class TestSetTraceFunc < Test::Unit::Tes https://github.com/ruby/ruby/blob/trunk/test/ruby/test_settracefunc.rb#L1188
       assert_equal([['call', :foo], ['return', :foo]], events, 'Bug #9759')
     ensure
     end
+  end
 
+  def test_recursive
+    assert_ruby_status [], %q{
+      stack = []
+      TracePoint.new(:c_call){|tp|
+        p 2
+        stack << tp.method_id
+      }.enable{
+        p 1
+      }
+      raise if stack != [:p, :hash, :inspect]
+    }, '[Bug #9940]'
   end
 end

--
ML: ruby-changes@q...
Info: http://www.atdot.net/~ko1/quickml/

[前][次][番号順一覧][スレッド一覧]