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/