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

ruby-changes:35919

From: ktsj <ko1@a...>
Date: Sat, 18 Oct 2014 20:46:49 +0900 (JST)
Subject: [ruby-changes:35919] ktsj:r48000 (trunk): * vm_core.h, vm.c, proc.c: fix GC mark miss on bindings.

ktsj	2014-10-18 20:46:31 +0900 (Sat, 18 Oct 2014)

  New Revision: 48000

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

  Log:
    * vm_core.h, vm.c, proc.c: fix GC mark miss on bindings.
      [ruby-dev:48616] [Bug #10368]
    
    * test/ruby/test_eval.rb: add a test code.

  Modified files:
    trunk/ChangeLog
    trunk/proc.c
    trunk/test/ruby/test_eval.rb
    trunk/vm.c
    trunk/vm_core.h
Index: ChangeLog
===================================================================
--- ChangeLog	(revision 47999)
+++ ChangeLog	(revision 48000)
@@ -1,3 +1,10 @@ https://github.com/ruby/ruby/blob/trunk/ChangeLog#L1
+Sat Oct 18 20:38:48 2014  Kazuki Tsujimoto  <kazuki@c...>
+
+	* vm_core.h, vm.c, proc.c: fix GC mark miss on bindings.
+	  [ruby-dev:48616] [Bug #10368]
+
+	* test/ruby/test_eval.rb: add a test code.
+
 Fri Oct 17 22:47:11 2014  Tanaka Akira  <akr@f...>
 
 	* pack.c (pack_unpack): Add casts for char references for 'u'.
Index: vm_core.h
===================================================================
--- vm_core.h	(revision 47999)
+++ vm_core.h	(revision 48000)
@@ -771,6 +771,7 @@ extern const rb_data_type_t ruby_binding https://github.com/ruby/ruby/blob/trunk/vm_core.h#L771
 typedef struct {
     VALUE env;
     VALUE path;
+    VALUE blockprocval;	/* for GC mark */
     unsigned short first_lineno;
 } rb_binding_t;
 
@@ -887,6 +888,7 @@ rb_block_t *rb_vm_control_frame_block_pt https://github.com/ruby/ruby/blob/trunk/vm_core.h#L888
 /* VM related object allocate functions */
 VALUE rb_thread_alloc(VALUE klass);
 VALUE rb_proc_wrap(VALUE klass, rb_proc_t *); /* may use with rb_proc_alloc */
+VALUE rb_binding_alloc(VALUE klass);
 
 /* for debug */
 extern void rb_vmdebug_stack_dump_raw(rb_thread_t *, rb_control_frame_t *);
@@ -908,6 +910,7 @@ int rb_thread_method_id_and_class(rb_thr https://github.com/ruby/ruby/blob/trunk/vm_core.h#L910
 VALUE rb_vm_invoke_proc(rb_thread_t *th, rb_proc_t *proc,
 			int argc, const VALUE *argv, const rb_block_t *blockptr);
 VALUE rb_vm_make_proc(rb_thread_t *th, const rb_block_t *block, VALUE klass);
+VALUE rb_vm_make_binding(rb_thread_t *th, const rb_control_frame_t *src_cfp);
 VALUE rb_vm_make_env_object(rb_thread_t *th, rb_control_frame_t *cfp);
 VALUE rb_vm_env_local_variables(VALUE envval);
 VALUE rb_binding_new_with_cfp(rb_thread_t *th, const rb_control_frame_t *src_cfp);
Index: proc.c
===================================================================
--- proc.c	(revision 47999)
+++ proc.c	(revision 48000)
@@ -247,6 +247,7 @@ binding_mark(void *ptr) https://github.com/ruby/ruby/blob/trunk/proc.c#L247
 	bind = ptr;
 	RUBY_MARK_UNLESS_NULL(bind->env);
 	RUBY_MARK_UNLESS_NULL(bind->path);
+	RUBY_MARK_UNLESS_NULL(bind->blockprocval);
     }
     RUBY_MARK_LEAVE("binding");
 }
@@ -267,8 +268,8 @@ const rb_data_type_t ruby_binding_data_t https://github.com/ruby/ruby/blob/trunk/proc.c#L268
     NULL, NULL, RUBY_TYPED_FREE_IMMEDIATELY
 };
 
-static VALUE
-binding_alloc(VALUE klass)
+VALUE
+rb_binding_alloc(VALUE klass)
 {
     VALUE obj;
     rb_binding_t *bind;
@@ -280,12 +281,13 @@ binding_alloc(VALUE klass) https://github.com/ruby/ruby/blob/trunk/proc.c#L281
 static VALUE
 binding_dup(VALUE self)
 {
-    VALUE bindval = binding_alloc(rb_cBinding);
+    VALUE bindval = rb_binding_alloc(rb_cBinding);
     rb_binding_t *src, *dst;
     GetBindingPtr(self, src);
     GetBindingPtr(bindval, dst);
     dst->env = src->env;
     dst->path = src->path;
+    dst->blockprocval = src->blockprocval;
     dst->first_lineno = src->first_lineno;
     return bindval;
 }
@@ -302,30 +304,7 @@ binding_clone(VALUE self) https://github.com/ruby/ruby/blob/trunk/proc.c#L304
 VALUE
 rb_binding_new_with_cfp(rb_thread_t *th, const rb_control_frame_t *src_cfp)
 {
-    rb_control_frame_t *cfp = rb_vm_get_binding_creatable_next_cfp(th, src_cfp);
-    rb_control_frame_t *ruby_level_cfp = rb_vm_get_ruby_level_next_cfp(th, src_cfp);
-    VALUE bindval, envval;
-    rb_binding_t *bind;
-
-    if (cfp == 0 || ruby_level_cfp == 0) {
-	rb_raise(rb_eRuntimeError, "Can't create Binding Object on top of Fiber.");
-    }
-
-    while (1) {
-	envval = rb_vm_make_env_object(th, cfp);
-	if (cfp == ruby_level_cfp) {
-	    break;
-	}
-	cfp = rb_vm_get_binding_creatable_next_cfp(th, RUBY_VM_PREVIOUS_CONTROL_FRAME(cfp));
-    }
-
-    bindval = binding_alloc(rb_cBinding);
-    GetBindingPtr(bindval, bind);
-    bind->env = envval;
-    bind->path = ruby_level_cfp->iseq->location.path;
-    bind->first_lineno = rb_vm_get_sourceline(ruby_level_cfp);
-
-    return bindval;
+    return rb_vm_make_binding(th, src_cfp);
 }
 
 VALUE
@@ -2485,9 +2464,10 @@ proc_binding(VALUE self) https://github.com/ruby/ruby/blob/trunk/proc.c#L2464
 	}
     }
 
-    bindval = binding_alloc(rb_cBinding);
+    bindval = rb_binding_alloc(rb_cBinding);
     GetBindingPtr(bindval, bind);
     bind->env = proc->envval;
+    bind->blockprocval = proc->blockprocval;
     if (RUBY_VM_NORMAL_ISEQ_P(proc->block.iseq)) {
 	bind->path = proc->block.iseq->location.path;
 	bind->first_lineno = FIX2INT(rb_iseq_first_lineno(proc->block.iseq->self));
Index: vm.c
===================================================================
--- vm.c	(revision 47999)
+++ vm.c	(revision 48000)
@@ -688,6 +688,39 @@ rb_vm_make_proc(rb_thread_t *th, const r https://github.com/ruby/ruby/blob/trunk/vm.c#L688
     return procval;
 }
 
+/* Binding */
+
+VALUE
+rb_vm_make_binding(rb_thread_t *th, const rb_control_frame_t *src_cfp)
+{
+    rb_control_frame_t *cfp = rb_vm_get_binding_creatable_next_cfp(th, src_cfp);
+    rb_control_frame_t *ruby_level_cfp = rb_vm_get_ruby_level_next_cfp(th, src_cfp);
+    VALUE bindval, envval;
+    rb_binding_t *bind;
+    VALUE blockprocval = 0;
+
+    if (cfp == 0 || ruby_level_cfp == 0) {
+	rb_raise(rb_eRuntimeError, "Can't create Binding Object on top of Fiber.");
+    }
+
+    while (1) {
+	envval = vm_make_env_object(th, cfp, &blockprocval);
+	if (cfp == ruby_level_cfp) {
+	    break;
+	}
+	cfp = rb_vm_get_binding_creatable_next_cfp(th, RUBY_VM_PREVIOUS_CONTROL_FRAME(cfp));
+    }
+
+    bindval = rb_binding_alloc(rb_cBinding);
+    GetBindingPtr(bindval, bind);
+    bind->env = envval;
+    bind->path = ruby_level_cfp->iseq->location.path;
+    bind->blockprocval = blockprocval;
+    bind->first_lineno = rb_vm_get_sourceline(ruby_level_cfp);
+
+    return bindval;
+}
+
 VALUE *
 rb_binding_add_dynavars(rb_binding_t *bind, int dyncount, const ID *dynvars)
 {
@@ -699,6 +732,7 @@ rb_binding_add_dynavars(rb_binding_t *bi https://github.com/ruby/ruby/blob/trunk/vm.c#L732
     NODE *node = 0;
     ID minibuf[4], *dyns = minibuf;
     VALUE idtmp = 0;
+    VALUE blockprocval = 0;
 
     if (dyncount < 0) return 0;
 
@@ -719,7 +753,8 @@ rb_binding_add_dynavars(rb_binding_t *bi https://github.com/ruby/ruby/blob/trunk/vm.c#L753
     ALLOCV_END(idtmp);
 
     vm_set_eval_stack(th, iseqval, 0, base_block);
-    bind->env = rb_vm_make_env_object(th, th->cfp);
+    bind->env = vm_make_env_object(th, th->cfp, &blockprocval);
+    bind->blockprocval = blockprocval;
     vm_pop_frame(th);
     GetEnvPtr(bind->env, env);
 
Index: test/ruby/test_eval.rb
===================================================================
--- test/ruby/test_eval.rb	(revision 47999)
+++ test/ruby/test_eval.rb	(revision 48000)
@@ -484,4 +484,19 @@ class TestEval < Test::Unit::TestCase https://github.com/ruby/ruby/blob/trunk/test/ruby/test_eval.rb#L484
 
     assert_same a, b
   end
+
+  def test_gced_binding_block
+    assert_normal_exit %q{
+      def m
+        binding
+      end
+      GC.stress = true
+      b = nil
+      tap do
+        b = m {}
+      end
+      0.times.to_a
+      b.eval('yield')
+    }, '[Bug #10368]'
+  end
 end

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

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