Skip to content

Commit 445bb45

Browse files
committed
Fixes [Bug #22883] eval isolation in Ractors for Prism
Add helper functions to compute isolation depth for eval contexts. Both Prism and parse.y parsers now use the same isolation detection, ensuring consistent behavior when accessing outer locals in Ractors.
1 parent 839b1fa commit 445bb45

File tree

2 files changed

+52
-21
lines changed

2 files changed

+52
-21
lines changed

bootstraptest/test_ractor.rb

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -754,6 +754,37 @@ def ractor_local_globals
754754
end
755755
}
756756

757+
# eval with outer locals in a Ractor raises SyntaxError
758+
# [Bug #22883]
759+
assert_equal 'SyntaxError', %q{
760+
outer = 42
761+
r = Ractor.new do
762+
eval("outer")
763+
end
764+
begin
765+
r.value
766+
rescue Ractor::RemoteError => e
767+
e.cause.class
768+
end
769+
}
770+
771+
# eval of an undefined name in a Ractor raises NameError
772+
assert_equal 'NameError', %q{
773+
r = Ractor.new do
774+
eval("totally_undefined_name")
775+
end
776+
begin
777+
r.value
778+
rescue Ractor::RemoteError => e
779+
e.cause.class
780+
end
781+
}
782+
783+
# eval of a local defined inside the Ractor works
784+
assert_equal '99', %q{
785+
Ractor.new { inner = 99; eval("inner").to_s }.value
786+
}
787+
757788
# ivar in shareable-objects are not allowed to access from non-main Ractor
758789
assert_equal "can not get unshareable values from instance variables of classes/modules from non-main Ractors", <<~'RUBY', frozen_string_literal: false
759790
class C

vm_eval.c

Lines changed: 21 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1669,6 +1669,24 @@ get_eval_default_path(void)
16691669
return eval_default_path;
16701670
}
16711671

1672+
static inline int
1673+
compute_isolated_depth_from_ep(const VALUE *ep)
1674+
{
1675+
int depth = 1;
1676+
while (1) {
1677+
if (VM_ENV_FLAGS(ep, VM_ENV_FLAG_ISOLATED)) return depth;
1678+
if (VM_ENV_LOCAL_P(ep)) return 0;
1679+
ep = VM_ENV_PREV_EP(ep);
1680+
depth++;
1681+
}
1682+
}
1683+
1684+
static inline int
1685+
compute_isolated_depth_from_block(const struct rb_block *blk)
1686+
{
1687+
return compute_isolated_depth_from_ep(vm_block_ep(blk));
1688+
}
1689+
16721690
static const rb_iseq_t *
16731691
pm_eval_make_iseq(VALUE src, VALUE fname, int line,
16741692
const struct rb_block *base_block)
@@ -1677,8 +1695,8 @@ pm_eval_make_iseq(VALUE src, VALUE fname, int line,
16771695
const rb_iseq_t *iseq = parent;
16781696
VALUE name = rb_fstring_lit("<compiled>");
16791697

1680-
// Conditionally enable coverage depending on the current mode:
16811698
int coverage_enabled = ((rb_get_coverage_mode() & COVERAGE_TARGET_EVAL) != 0) ? 1 : 0;
1699+
int isolated_depth = compute_isolated_depth_from_block(base_block);
16821700

16831701
if (!fname) {
16841702
fname = rb_source_location(&line);
@@ -1872,7 +1890,7 @@ pm_eval_make_iseq(VALUE src, VALUE fname, int line,
18721890
#undef FORWARDING_ALL_STR
18731891

18741892
int error_state;
1875-
iseq = pm_iseq_new_eval(&result.node, name, fname, Qnil, line, parent, 0, &error_state);
1893+
iseq = pm_iseq_new_eval(&result.node, name, fname, Qnil, line, parent, isolated_depth, &error_state);
18761894

18771895
pm_scope_node_t *prev = result.node.previous;
18781896
while (prev) {
@@ -1908,27 +1926,9 @@ eval_make_iseq(VALUE src, VALUE fname, int line,
19081926
rb_iseq_t *iseq = NULL;
19091927
VALUE ast_value;
19101928
rb_ast_t *ast;
1911-
int isolated_depth = 0;
19121929

1913-
// Conditionally enable coverage depending on the current mode:
19141930
int coverage_enabled = (rb_get_coverage_mode() & COVERAGE_TARGET_EVAL) != 0;
1915-
1916-
{
1917-
int depth = 1;
1918-
const VALUE *ep = vm_block_ep(base_block);
1919-
1920-
while (1) {
1921-
if (VM_ENV_FLAGS(ep, VM_ENV_FLAG_ISOLATED)) {
1922-
isolated_depth = depth;
1923-
break;
1924-
}
1925-
else if (VM_ENV_LOCAL_P(ep)) {
1926-
break;
1927-
}
1928-
ep = VM_ENV_PREV_EP(ep);
1929-
depth++;
1930-
}
1931-
}
1931+
int isolated_depth = compute_isolated_depth_from_block(base_block);
19321932

19331933
if (!fname) {
19341934
fname = rb_source_location(&line);

0 commit comments

Comments
 (0)