Skip to content

Commit fccbc2d

Browse files
committed
* 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/trunk@59063 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
1 parent b25237f commit fccbc2d

2 files changed

Lines changed: 26 additions & 4 deletions

File tree

proc.c

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -386,8 +386,9 @@ bind_eval(int argc, VALUE *argv, VALUE bindval)
386386
}
387387

388388
static const VALUE *
389-
get_local_variable_ptr(const rb_env_t *env, ID lid)
389+
get_local_variable_ptr(const rb_env_t **envp, ID lid)
390390
{
391+
const rb_env_t *env = *envp;
391392
do {
392393
if (!VM_ENV_FLAGS(env->ep, VM_FRAME_FLAG_CFRAME)) {
393394
const rb_iseq_t *iseq = env->iseq;
@@ -397,15 +398,18 @@ get_local_variable_ptr(const rb_env_t *env, ID lid)
397398

398399
for (i=0; i<iseq->body->local_table_size; i++) {
399400
if (iseq->body->local_table[i] == lid) {
401+
*envp = env;
400402
return &env->env[i];
401403
}
402404
}
403405
}
404406
else {
407+
*envp = NULL;
405408
return NULL;
406409
}
407410
} while ((env = rb_vm_env_prev_env(env)) != NULL);
408411

412+
*envp = NULL;
409413
return NULL;
410414
}
411415

@@ -488,12 +492,14 @@ bind_local_variable_get(VALUE bindval, VALUE sym)
488492
ID lid = check_local_id(bindval, &sym);
489493
const rb_binding_t *bind;
490494
const VALUE *ptr;
495+
const rb_env_t *env;
491496

492497
if (!lid) goto undefined;
493498

494499
GetBindingPtr(bindval, bind);
495500

496-
if ((ptr = get_local_variable_ptr(VM_ENV_ENVVAL_PTR(vm_block_ep(&bind->block)), lid)) == NULL) {
501+
env = VM_ENV_ENVVAL_PTR(vm_block_ep(&bind->block));
502+
if ((ptr = get_local_variable_ptr(&env, lid)) == NULL) {
497503
sym = ID2SYM(lid);
498504
undefined:
499505
rb_name_err_raise("local variable `%1$s' not defined for %2$s",
@@ -540,7 +546,7 @@ bind_local_variable_set(VALUE bindval, VALUE sym, VALUE val)
540546

541547
GetBindingPtr(bindval, bind);
542548
env = VM_ENV_ENVVAL_PTR(vm_block_ep(&bind->block));
543-
if ((ptr = get_local_variable_ptr(env, lid)) == NULL) {
549+
if ((ptr = get_local_variable_ptr(&env, lid)) == NULL) {
544550
/* not found. create new env */
545551
ptr = rb_binding_add_dynavars(bindval, bind, 1, &lid);
546552
env = VM_ENV_ENVVAL_PTR(vm_block_ep(&bind->block));
@@ -573,11 +579,13 @@ bind_local_variable_defined_p(VALUE bindval, VALUE sym)
573579
{
574580
ID lid = check_local_id(bindval, &sym);
575581
const rb_binding_t *bind;
582+
const rb_env_t *env;
576583

577584
if (!lid) return Qfalse;
578585

579586
GetBindingPtr(bindval, bind);
580-
return get_local_variable_ptr(VM_ENV_ENVVAL_PTR(vm_block_ep(&bind->block)), lid) ? Qtrue : Qfalse;
587+
env = VM_ENV_ENVVAL_PTR(vm_block_ep(&bind->block));
588+
return get_local_variable_ptr(&env, lid) ? Qtrue : Qfalse;
581589
}
582590

583591
/*

test/ruby/test_proc.rb

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1324,6 +1324,20 @@ def test_local_variable_set
13241324
assert_equal(20, b.eval("b"))
13251325
end
13261326

1327+
def test_local_variable_set_wb
1328+
assert_ruby_status([], <<-'end;', '[Bug #13605]')
1329+
b = binding
1330+
n = 20_000
1331+
1332+
n.times do |i|
1333+
v = rand(2_000)
1334+
name = "n#{v}"
1335+
value = Object.new
1336+
b.local_variable_set name, value
1337+
end
1338+
end;
1339+
end
1340+
13271341
def test_local_variable_defined?
13281342
b = get_binding
13291343
assert_equal(true, b.local_variable_defined?(:a))

0 commit comments

Comments
 (0)