summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authornagachika <nagachika@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2017-08-04 15:06:22 +0000
committernagachika <nagachika@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2017-08-04 15:06:22 +0000
commit8343847b6ba6f1baf58b8a86429a747d5c5fdec8 (patch)
tree4c738fb78420a85a6db4d9997c8bbbbbefb107ea
parentb7f7b0a2d25071dd8fe09b3f313168bf7f939cc7 (diff)
merge revision(s) 59063: [Backport #13605]
* proc.c (get_local_variable_ptr): return found env ptr. Returned env will be used by write barrier at `bind_local_variable_set()'. [Bug #13605] * test/ruby/test_proc.rb: add a test for this issue. git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/branches/ruby_2_4@59503 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
-rw-r--r--proc.c16
-rw-r--r--test/ruby/test_proc.rb14
-rw-r--r--version.h2
3 files changed, 27 insertions, 5 deletions
diff --git a/proc.c b/proc.c
index da8c763799..c23658e4bf 100644
--- a/proc.c
+++ b/proc.c
@@ -392,8 +392,9 @@ bind_eval(int argc, VALUE *argv, VALUE bindval)
}
static const VALUE *
-get_local_variable_ptr(const rb_env_t *env, ID lid)
+get_local_variable_ptr(const rb_env_t **envp, ID lid)
{
+ const rb_env_t *env = *envp;
do {
if (!VM_ENV_FLAGS(env->ep, VM_FRAME_FLAG_CFRAME)) {
const rb_iseq_t *iseq = env->iseq;
@@ -403,15 +404,18 @@ get_local_variable_ptr(const rb_env_t *env, ID lid)
for (i=0; i<iseq->body->local_table_size; i++) {
if (iseq->body->local_table[i] == lid) {
+ *envp = env;
return &env->env[i];
}
}
}
else {
+ *envp = NULL;
return NULL;
}
} while ((env = rb_vm_env_prev_env(env)) != NULL);
+ *envp = NULL;
return NULL;
}
@@ -494,12 +498,14 @@ bind_local_variable_get(VALUE bindval, VALUE sym)
ID lid = check_local_id(bindval, &sym);
const rb_binding_t *bind;
const VALUE *ptr;
+ const rb_env_t *env;
if (!lid) goto undefined;
GetBindingPtr(bindval, bind);
- if ((ptr = get_local_variable_ptr(VM_ENV_ENVVAL_PTR(vm_block_ep(&bind->block)), lid)) == NULL) {
+ env = VM_ENV_ENVVAL_PTR(vm_block_ep(&bind->block));
+ if ((ptr = get_local_variable_ptr(&env, lid)) == NULL) {
sym = ID2SYM(lid);
undefined:
rb_name_err_raise("local variable `%1$s' not defined for %2$s",
@@ -546,7 +552,7 @@ bind_local_variable_set(VALUE bindval, VALUE sym, VALUE val)
GetBindingPtr(bindval, bind);
env = VM_ENV_ENVVAL_PTR(vm_block_ep(&bind->block));
- if ((ptr = get_local_variable_ptr(env, lid)) == NULL) {
+ if ((ptr = get_local_variable_ptr(&env, lid)) == NULL) {
/* not found. create new env */
ptr = rb_binding_add_dynavars(bind, 1, &lid);
env = VM_ENV_ENVVAL_PTR(vm_block_ep(&bind->block));
@@ -579,11 +585,13 @@ bind_local_variable_defined_p(VALUE bindval, VALUE sym)
{
ID lid = check_local_id(bindval, &sym);
const rb_binding_t *bind;
+ const rb_env_t *env;
if (!lid) return Qfalse;
GetBindingPtr(bindval, bind);
- return get_local_variable_ptr(VM_ENV_ENVVAL_PTR(vm_block_ep(&bind->block)), lid) ? Qtrue : Qfalse;
+ env = VM_ENV_ENVVAL_PTR(vm_block_ep(&bind->block));
+ return get_local_variable_ptr(&env, lid) ? Qtrue : Qfalse;
}
/*
diff --git a/test/ruby/test_proc.rb b/test/ruby/test_proc.rb
index b46c0a901b..f34adae24e 100644
--- a/test/ruby/test_proc.rb
+++ b/test/ruby/test_proc.rb
@@ -1322,6 +1322,20 @@ class TestProc < Test::Unit::TestCase
assert_equal(20, b.eval("b"))
end
+ def test_local_variable_set_wb
+ assert_ruby_status([], <<-'end;', '[Bug #13605]')
+ b = binding
+ n = 20_000
+
+ n.times do |i|
+ v = rand(2_000)
+ name = "n#{v}"
+ value = Object.new
+ b.local_variable_set name, value
+ end
+ end;
+ end
+
def test_local_variable_defined?
b = get_binding
assert_equal(true, b.local_variable_defined?(:a))
diff --git a/version.h b/version.h
index b89d37abf8..4fa05b4386 100644
--- a/version.h
+++ b/version.h
@@ -1,6 +1,6 @@
#define RUBY_VERSION "2.4.2"
#define RUBY_RELEASE_DATE "2017-08-04"
-#define RUBY_PATCHLEVEL 169
+#define RUBY_PATCHLEVEL 170
#define RUBY_RELEASE_YEAR 2017
#define RUBY_RELEASE_MONTH 8