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

ruby-changes:38030

From: nobu <ko1@a...>
Date: Sun, 29 Mar 2015 11:51:40 +0900 (JST)
Subject: [ruby-changes:38030] nobu:r50111 (trunk): proc.c: replicate method env

nobu	2015-03-29 11:51:34 +0900 (Sun, 29 Mar 2015)

  New Revision: 50111

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

  Log:
    proc.c: replicate method env
    
    * proc.c (proc_binding): replicate env from method object, and
      allocate the local variable area for the iseq local table.
      [ruby-core:68673] [Bug #11012]

  Modified files:
    trunk/ChangeLog
    trunk/proc.c
    trunk/test/ruby/test_method.rb
Index: ChangeLog
===================================================================
--- ChangeLog	(revision 50110)
+++ ChangeLog	(revision 50111)
@@ -1,3 +1,9 @@ https://github.com/ruby/ruby/blob/trunk/ChangeLog#L1
+Sun Mar 29 11:51:32 2015  Nobuyoshi Nakada  <nobu@r...>
+
+	* proc.c (proc_binding): replicate env from method object, and
+	  allocate the local variable area for the iseq local table.
+	  [ruby-core:68673] [Bug #11012]
+
 Sat Mar 28 09:19:41 2015  NARUSE, Yui  <naruse@r...>
 
 	* ext/date/extconf.rb: try_cflags("-std=iso9899:1999") [Bug #10906]
Index: proc.c
===================================================================
--- proc.c	(revision 50110)
+++ proc.c	(revision 50111)
@@ -2493,22 +2493,40 @@ static VALUE https://github.com/ruby/ruby/blob/trunk/proc.c#L2493
 proc_binding(VALUE self)
 {
     rb_proc_t *proc;
-    VALUE bindval;
+    VALUE bindval, envval;
     rb_binding_t *bind;
     rb_iseq_t *iseq;
 
     GetProcPtr(self, proc);
+    envval = proc->envval;
     iseq = proc->block.iseq;
     if (RUBY_VM_IFUNC_P(iseq)) {
+	rb_env_t *env;
 	if (!IS_METHOD_PROC_ISEQ(iseq)) {
 	    rb_raise(rb_eArgError, "Can't create Binding from C level Proc");
 	}
 	iseq = rb_method_get_iseq((VALUE)((struct vm_ifunc *)iseq)->data);
+	GetEnvPtr(envval, env);
+	if (env->local_size < iseq->local_size) {
+	    int prev_local_size = env->local_size;
+	    int local_size = iseq->local_size;
+	    VALUE newenvval = TypedData_Wrap_Struct(RBASIC_CLASS(envval), RTYPEDDATA_TYPE(envval), 0);
+	    rb_env_t *newenv = xmalloc(sizeof(rb_env_t) + ((local_size + 1) * sizeof(VALUE)));
+	    RTYPEDDATA_DATA(newenvval) = newenv;
+	    newenv->env_size = local_size + 2;
+	    newenv->local_size = local_size;
+	    newenv->prev_envval = env->prev_envval;
+	    newenv->block = env->block;
+	    MEMCPY(newenv->env, env->env, VALUE, prev_local_size + 1);
+	    rb_mem_clear(newenv->env + prev_local_size + 1, local_size - prev_local_size);
+	    newenv->env[local_size + 1] = newenvval;
+	    envval = newenvval;
+	}
     }
 
     bindval = rb_binding_alloc(rb_cBinding);
     GetBindingPtr(bindval, bind);
-    bind->env = proc->envval;
+    bind->env = envval;
     bind->blockprocval = proc->blockprocval;
     if (RUBY_VM_NORMAL_ISEQ_P(iseq)) {
 	bind->path = iseq->location.path;
Index: test/ruby/test_method.rb
===================================================================
--- test/ruby/test_method.rb	(revision 50110)
+++ test/ruby/test_method.rb	(revision 50111)
@@ -886,4 +886,18 @@ class TestMethod < Test::Unit::TestCase https://github.com/ruby/ruby/blob/trunk/test/ruby/test_method.rb#L886
       obj.bar
     end
   end
+
+  def test_to_proc_binding
+    bug11012 = '[ruby-core:68673] [Bug #11012]'
+    class << (obj = Object.new)
+      src = 1000.times.map {|i|"v#{i} = nil"}.join("\n")
+      eval("def foo()\n""#{src}\n""end")
+    end
+
+    b = obj.method(:foo).to_proc.binding
+    b.local_variables.each_with_index {|n, i|
+      b.local_variable_set(n, i)
+    }
+    assert_equal([998, 999], %w[v998 v999].map {|n| b.local_variable_get(n)}, bug11012)
+  end
 end

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

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