check isolated Proc more strictly

Isolated Proc prohibit to access outer local variables, but it was
violated by binding and so on, so they should be error.
This commit is contained in:
Koichi Sasada 2020-10-23 13:27:21 +09:00
parent bf951c763d
commit 07c03bc309
Notes: git 2020-10-29 23:43:27 +09:00
9 changed files with 264 additions and 52 deletions

View File

@ -1319,9 +1319,12 @@ new_child_iseq(rb_iseq_t *iseq, const NODE *const node,
ast.line_count = -1;
debugs("[new_child_iseq]> ---------------------------------------\n");
int isolated_depth = ISEQ_COMPILE_DATA(iseq)->isolated_depth;
ret_iseq = rb_iseq_new_with_opt(&ast, name,
rb_iseq_path(iseq), rb_iseq_realpath(iseq),
INT2FIX(line_no), parent, type, ISEQ_COMPILE_DATA(iseq)->option);
INT2FIX(line_no), parent,
isolated_depth ? isolated_depth + 1 : 0,
type, ISEQ_COMPILE_DATA(iseq)->option);
debugs("[new_child_iseq]< ---------------------------------------\n");
return ret_iseq;
}
@ -1601,15 +1604,52 @@ iseq_block_param_id_p(const rb_iseq_t *iseq, ID id, int *pidx, int *plevel)
}
static void
check_access_outer_variables(const rb_iseq_t *iseq, int level)
access_outer_variables(const rb_iseq_t *iseq, int level, ID id, bool write)
{
// set access_outer_variables
int isolated_depth = ISEQ_COMPILE_DATA(iseq)->isolated_depth;
if (isolated_depth && level >= isolated_depth) {
if (id == rb_intern("yield")) {
COMPILE_ERROR(iseq, ISEQ_LAST_LINE(iseq), "can not yield from isolated Proc", rb_id2name(id));
}
else {
COMPILE_ERROR(iseq, ISEQ_LAST_LINE(iseq), "can not access variable `%s' from isolated Proc", rb_id2name(id));
}
}
for (int i=0; i<level; i++) {
iseq->body->access_outer_variables = TRUE;
VALUE val;
struct rb_id_table *ovs = iseq->body->outer_variables;
if (!ovs) {
ovs = iseq->body->outer_variables = rb_id_table_create(8);
}
if (rb_id_table_lookup(iseq->body->outer_variables, id, &val)) {
if (write && !val) {
rb_id_table_insert(iseq->body->outer_variables, id, Qtrue);
}
}
else {
rb_id_table_insert(iseq->body->outer_variables, id, write ? Qtrue : Qfalse);
}
iseq = iseq->body->parent_iseq;
}
}
static ID
iseq_lvar_id(const rb_iseq_t *iseq, int idx, int level)
{
for (int i=0; i<level; i++) {
iseq = iseq->body->parent_iseq;
}
ID id = iseq->body->local_table[iseq->body->local_table_size - idx];
// fprintf(stderr, "idx:%d level:%d ID:%s\n", idx, level, rb_id2name(id));
return id;
}
static void
iseq_add_getlocal(rb_iseq_t *iseq, LINK_ANCHOR *const seq, int line, int idx, int level)
{
@ -1619,7 +1659,7 @@ iseq_add_getlocal(rb_iseq_t *iseq, LINK_ANCHOR *const seq, int line, int idx, in
else {
ADD_INSN2(seq, line, getlocal, INT2FIX((idx) + VM_ENV_DATA_SIZE - 1), INT2FIX(level));
}
check_access_outer_variables(iseq, level);
if (level > 0) access_outer_variables(iseq, level, iseq_lvar_id(iseq, idx, level), Qfalse);
}
static void
@ -1631,7 +1671,7 @@ iseq_add_setlocal(rb_iseq_t *iseq, LINK_ANCHOR *const seq, int line, int idx, in
else {
ADD_INSN2(seq, line, setlocal, INT2FIX((idx) + VM_ENV_DATA_SIZE - 1), INT2FIX(level));
}
check_access_outer_variables(iseq, level);
if (level > 0) access_outer_variables(iseq, level, iseq_lvar_id(iseq, idx, level), Qtrue);
}
@ -8215,7 +8255,12 @@ iseq_compile_each0(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *node, in
ADD_INSN(ret, line, pop);
}
iseq->body->access_outer_variables = TRUE;
int level = 0;
const rb_iseq_t *tmp_iseq = iseq;
for (; tmp_iseq != iseq->body->local_iseq; level++ ) {
tmp_iseq = tmp_iseq->body->parent_iseq;
}
if (level > 0) access_outer_variables(iseq, level, rb_intern("yield"), true);
break;
}
case NODE_LVAR:{

39
iseq.c
View File

@ -130,6 +130,7 @@ rb_iseq_free(const rb_iseq_t *iseq)
ruby_xfree((void *)body->param.keyword);
}
compile_data_free(ISEQ_COMPILE_DATA(iseq));
if (body->outer_variables) rb_id_table_free(body->outer_variables);
ruby_xfree(body);
}
@ -575,8 +576,7 @@ new_arena(void)
static VALUE
prepare_iseq_build(rb_iseq_t *iseq,
VALUE name, VALUE path, VALUE realpath, VALUE first_lineno, const rb_code_location_t *code_location, const int node_id,
const rb_iseq_t *parent, enum iseq_type type,
const rb_compile_option_t *option)
const rb_iseq_t *parent, int isolated_depth, enum iseq_type type, const rb_compile_option_t *option)
{
VALUE coverage = Qfalse;
VALUE err_info = Qnil;
@ -603,11 +603,11 @@ prepare_iseq_build(rb_iseq_t *iseq,
ISEQ_COMPILE_DATA(iseq)->node.storage_head = ISEQ_COMPILE_DATA(iseq)->node.storage_current = new_arena();
ISEQ_COMPILE_DATA(iseq)->insn.storage_head = ISEQ_COMPILE_DATA(iseq)->insn.storage_current = new_arena();
ISEQ_COMPILE_DATA(iseq)->isolated_depth = isolated_depth;
ISEQ_COMPILE_DATA(iseq)->option = option;
ISEQ_COMPILE_DATA(iseq)->ivar_cache_table = NULL;
ISEQ_COMPILE_DATA(iseq)->builtin_function_table = GET_VM()->builtin_function_table;
if (option->coverage_enabled) {
VALUE coverages = rb_get_coverages();
@ -794,8 +794,8 @@ rb_iseq_t *
rb_iseq_new(const rb_ast_body_t *ast, VALUE name, VALUE path, VALUE realpath,
const rb_iseq_t *parent, enum iseq_type type)
{
return rb_iseq_new_with_opt(ast, name, path, realpath, INT2FIX(0), parent, type,
&COMPILE_OPTION_DEFAULT);
return rb_iseq_new_with_opt(ast, name, path, realpath, INT2FIX(0), parent,
0, type, &COMPILE_OPTION_DEFAULT);
}
rb_iseq_t *
@ -810,8 +810,8 @@ rb_iseq_new_top(const rb_ast_body_t *ast, VALUE name, VALUE path, VALUE realpath
}
}
return rb_iseq_new_with_opt(ast, name, path, realpath, INT2FIX(0), parent, ISEQ_TYPE_TOP,
&COMPILE_OPTION_DEFAULT);
return rb_iseq_new_with_opt(ast, name, path, realpath, INT2FIX(0), parent, 0,
ISEQ_TYPE_TOP, &COMPILE_OPTION_DEFAULT);
}
rb_iseq_t *
@ -819,7 +819,14 @@ rb_iseq_new_main(const rb_ast_body_t *ast, VALUE path, VALUE realpath, const rb_
{
return rb_iseq_new_with_opt(ast, rb_fstring_lit("<main>"),
path, realpath, INT2FIX(0),
parent, ISEQ_TYPE_MAIN, &COMPILE_OPTION_DEFAULT);
parent, 0, ISEQ_TYPE_MAIN, &COMPILE_OPTION_DEFAULT);
}
rb_iseq_t *
rb_iseq_new_eval(const rb_ast_body_t *ast, VALUE name, VALUE path, VALUE realpath, VALUE first_lineno, const rb_iseq_t *parent, int isolated_depth)
{
return rb_iseq_new_with_opt(ast, name, path, realpath, first_lineno,
parent, isolated_depth, ISEQ_TYPE_EVAL, &COMPILE_OPTION_DEFAULT);
}
static inline rb_iseq_t *
@ -838,8 +845,8 @@ iseq_translate(rb_iseq_t *iseq)
rb_iseq_t *
rb_iseq_new_with_opt(const rb_ast_body_t *ast, VALUE name, VALUE path, VALUE realpath,
VALUE first_lineno, const rb_iseq_t *parent,
enum iseq_type type, const rb_compile_option_t *option)
VALUE first_lineno, const rb_iseq_t *parent, int isolated_depth,
enum iseq_type type, const rb_compile_option_t *option)
{
const NODE *node = ast ? ast->root : 0;
/* TODO: argument check */
@ -854,7 +861,7 @@ rb_iseq_new_with_opt(const rb_ast_body_t *ast, VALUE name, VALUE path, VALUE rea
}
if (ast && ast->compile_option) rb_iseq_make_compile_option(&new_opt, ast->compile_option);
prepare_iseq_build(iseq, name, path, realpath, first_lineno, node ? &node->nd_loc : NULL, node ? nd_node_id(node) : -1, parent, type, &new_opt);
prepare_iseq_build(iseq, name, path, realpath, first_lineno, node ? &node->nd_loc : NULL, node ? nd_node_id(node) : -1, parent, isolated_depth, type, &new_opt);
rb_iseq_compile_node(iseq, node);
finish_iseq_build(iseq);
@ -873,7 +880,7 @@ rb_iseq_new_with_callback(
rb_iseq_t *iseq = iseq_alloc();
if (!option) option = &COMPILE_OPTION_DEFAULT;
prepare_iseq_build(iseq, name, path, realpath, first_lineno, NULL, -1, parent, type, option);
prepare_iseq_build(iseq, name, path, realpath, first_lineno, NULL, -1, parent, 0, type, option);
rb_iseq_compile_callback(iseq, ifunc);
finish_iseq_build(iseq);
@ -986,7 +993,7 @@ iseq_load(VALUE data, const rb_iseq_t *parent, VALUE opt)
make_compile_option(&option, opt);
option.peephole_optimization = FALSE; /* because peephole optimization can modify original iseq */
prepare_iseq_build(iseq, name, path, realpath, first_lineno, &tmp_loc, NUM2INT(node_id),
parent, (enum iseq_type)iseq_type, &option);
parent, 0, (enum iseq_type)iseq_type, &option);
rb_iseq_build_from_ary(iseq, misc, locals, params, exception, body);
@ -1054,7 +1061,7 @@ rb_iseq_compile_with_option(VALUE src, VALUE file, VALUE realpath, VALUE line, V
else {
INITIALIZED VALUE label = rb_fstring_lit("<compiled>");
iseq = rb_iseq_new_with_opt(&ast->body, label, file, realpath, line,
0, ISEQ_TYPE_TOP, &option);
NULL, 0, ISEQ_TYPE_TOP, &option);
rb_ast_dispose(ast);
}
@ -1310,7 +1317,7 @@ iseqw_s_compile_file(int argc, VALUE *argv, VALUE self)
ret = iseqw_new(rb_iseq_new_with_opt(&ast->body, rb_fstring_lit("<main>"),
file,
rb_realpath_internal(Qnil, file, 1),
line, NULL, ISEQ_TYPE_TOP, &option));
line, NULL, 0, ISEQ_TYPE_TOP, &option));
rb_ast_dispose(ast);
return ret;
}

1
iseq.h
View File

@ -105,6 +105,7 @@ struct iseq_compile_data {
int last_line;
int label_no;
int node_level;
int isolated_depth;
unsigned int ci_index;
const rb_compile_option_t *option;
struct rb_id_table *ivar_cache_table;

9
proc.c
View File

@ -424,7 +424,11 @@ 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;
if (VM_ENV_FLAGS(env->ep, VM_ENV_FLAG_ISOLATED)) {
return NULL;
}
const rb_iseq_t *iseq = env->iseq;
unsigned int i;
VM_ASSERT(rb_obj_is_iseq((VALUE)iseq));
@ -3245,6 +3249,8 @@ proc_binding(VALUE self)
GetProcPtr(self, proc);
block = &proc->block;
if (proc->is_isolated) rb_raise(rb_eArgError, "Can't create Binding from isolated Proc");
again:
switch (vm_block_type(block)) {
case block_type_iseq:
@ -4065,6 +4071,7 @@ Init_Proc(void)
rb_define_method(rb_cProc, "source_location", rb_proc_location, 0);
rb_define_method(rb_cProc, "parameters", rb_proc_parameters, 0);
rb_define_method(rb_cProc, "ruby2_keywords", proc_ruby2_keywords, 0);
// rb_define_method(rb_cProc, "isolate", rb_proc_isolate, 0); is not accepted.
/* Exceptions */
rb_eLocalJumpError = rb_define_class("LocalJumpError", rb_eStandardError);

View File

@ -202,7 +202,7 @@ prelude_eval(VALUE code, VALUE name, int line)
rb_ast_t *ast = prelude_ast(name, code, line);
rb_iseq_eval(rb_iseq_new_with_opt(&ast->body, name, name, Qnil, INT2FIX(line),
NULL, ISEQ_TYPE_TOP, &optimization));
NULL, 0, ISEQ_TYPE_TOP, &optimization));
rb_ast_dispose(ast);
}
COMPILER_WARNING_POP

View File

@ -1538,6 +1538,57 @@ class TestProc < Test::Unit::TestCase
assert_equal(42, Module.new { extend self
def m1(&b) b end; def m2(); m1 { next 42 } end }.m2.call)
end
def test_isolate
assert_raise_with_message ArgumentError, /\(a\)/ do
a = :a
Proc.new{p a}.isolate.call
end
assert_raise_with_message ArgumentError, /\(a\)/ do
a = :a
1.times{
Proc.new{p a}.isolate.call
}
end
assert_raise_with_message ArgumentError, /yield/ do
Proc.new{yield}.isolate.call
end
# binding
:a.tap{|a|
:b.tap{|b|
Proc.new{
:c.tap{|c|
assert_equal :c, eval('c')
assert_raise_with_message SyntaxError, /\`a\'/ do
eval('p a')
end
assert_raise_with_message SyntaxError, /\`b\'/ do
eval('p b')
end
assert_raise_with_message SyntaxError, /can not yield from isolated Proc/ do
eval('p yield')
end
assert_equal :c, binding.local_variable_get(:c)
assert_raise_with_message NameError, /local variable \`a\' is not defined/ do
binding.local_variable_get(:a)
end
assert_equal [:c], local_variables
assert_equal [:c], binding.local_variables
}
}.isolate.call
}
}
end if proc{}.respond_to? :isolate
end
class TestProcKeywords < Test::Unit::TestCase

111
vm.c
View File

@ -739,18 +739,17 @@ vm_make_env_each(const rb_execution_context_t * const ec, rb_control_frame_t *co
if (!VM_ENV_LOCAL_P(ep)) {
const VALUE *prev_ep = VM_ENV_PREV_EP(ep);
if (!VM_ENV_ESCAPED_P(prev_ep)) {
rb_control_frame_t *prev_cfp = RUBY_VM_PREVIOUS_CONTROL_FRAME(cfp);
if (!VM_ENV_ESCAPED_P(prev_ep)) {
rb_control_frame_t *prev_cfp = RUBY_VM_PREVIOUS_CONTROL_FRAME(cfp);
while (prev_cfp->ep != prev_ep) {
prev_cfp = RUBY_VM_PREVIOUS_CONTROL_FRAME(prev_cfp);
VM_ASSERT(prev_cfp->ep != NULL);
}
while (prev_cfp->ep != prev_ep) {
prev_cfp = RUBY_VM_PREVIOUS_CONTROL_FRAME(prev_cfp);
VM_ASSERT(prev_cfp->ep != NULL);
}
vm_make_env_each(ec, prev_cfp);
VM_FORCE_WRITE_SPECIAL_CONST(&ep[VM_ENV_DATA_INDEX_SPECVAL], VM_GUARDED_PREV_EP(prev_cfp->ep));
}
vm_make_env_each(ec, prev_cfp);
VM_FORCE_WRITE_SPECIAL_CONST(&ep[VM_ENV_DATA_INDEX_SPECVAL], VM_GUARDED_PREV_EP(prev_cfp->ep));
}
}
else {
VALUE block_handler = VM_ENV_BLOCK_HANDLER(ep);
@ -836,7 +835,8 @@ rb_vm_env_prev_env(const rb_env_t *env)
return NULL;
}
else {
return VM_ENV_ENVVAL_PTR(VM_ENV_PREV_EP(ep));
const VALUE *prev_ep = VM_ENV_PREV_EP(ep);
return VM_ENV_ENVVAL_PTR(prev_ep);
}
}
@ -855,6 +855,7 @@ static void
collect_local_variables_in_env(const rb_env_t *env, const struct local_var_list *vars)
{
do {
if (VM_ENV_FLAGS(env->ep, VM_ENV_FLAG_ISOLATED)) break;
collect_local_variables_in_iseq(env->iseq, vars);
} while ((env = rb_vm_env_prev_env(env)) != NULL);
}
@ -963,17 +964,97 @@ rb_proc_dup(VALUE self)
return procval;
}
struct collect_outer_variable_name_data {
VALUE ary;
bool yield;
};
static enum rb_id_table_iterator_result
collect_outer_variable_names(ID id, VALUE val, void *ptr)
{
struct collect_outer_variable_name_data *data = (struct collect_outer_variable_name_data *)ptr;
if (id == rb_intern("yield")) {
data->yield = true;
}
else {
if (data->ary == Qfalse) data->ary = rb_ary_new();
rb_ary_push(data->ary, rb_id2str(id));
}
return ID_TABLE_CONTINUE;
}
static const rb_env_t *
env_copy(const VALUE *src_ep)
{
const rb_env_t *src_env = (rb_env_t *)VM_ENV_ENVVAL(src_ep);
VALUE *env_body = ZALLOC_N(VALUE, src_env->env_size); // fill with Qfalse
VALUE *ep = &env_body[src_env->env_size - 2];
VM_ASSERT(src_env->ep == src_ep);
ep[VM_ENV_DATA_INDEX_ME_CREF] = src_ep[VM_ENV_DATA_INDEX_ME_CREF];
ep[VM_ENV_DATA_INDEX_FLAGS] = src_ep[VM_ENV_DATA_INDEX_FLAGS] | VM_ENV_FLAG_ISOLATED;
if (!VM_ENV_LOCAL_P(src_ep)) {
const VALUE *prev_ep = VM_ENV_PREV_EP(src_env->ep);
const rb_env_t *new_prev_env = env_copy(prev_ep);
ep[VM_ENV_DATA_INDEX_SPECVAL] = VM_GUARDED_PREV_EP(new_prev_env->ep);
}
else {
ep[VM_ENV_DATA_INDEX_SPECVAL] = VM_BLOCK_HANDLER_NONE;
}
return vm_env_new(ep, env_body, src_env->env_size, src_env->iseq);
}
static void
proc_isolate_env(VALUE self, rb_proc_t *proc)
{
const struct rb_captured_block *captured = &proc->block.as.captured;
const rb_env_t *env = env_copy(captured->ep);
*((const VALUE **)&proc->block.as.captured.ep) = env->ep;
RB_OBJ_WRITTEN(self, Qundef, env);
}
VALUE
rb_proc_isolate_bang(VALUE self)
{
// check accesses
const rb_iseq_t *iseq = vm_proc_iseq(self);
if (iseq && iseq->body->access_outer_variables) {
rb_raise(rb_eArgError, "can not isolate a Proc because it can accesses outer variables.");
if (iseq) {
rb_proc_t *proc = (rb_proc_t *)RTYPEDDATA_DATA(self);
if (proc->block.type != block_type_iseq) rb_raise(rb_eRuntimeError, "not supported yet");
if (iseq->body->outer_variables) {
struct collect_outer_variable_name_data data = {
.ary = Qfalse,
.yield = false,
};
rb_id_table_foreach(iseq->body->outer_variables, collect_outer_variable_names, (void *)&data);
if (data.ary != Qfalse) {
VALUE str = rb_ary_join(data.ary, rb_str_new2(", "));
if (data.yield) {
rb_raise(rb_eArgError, "can not isolate a Proc because it accesses outer variables (%s) and uses `yield'.",
StringValueCStr(str));
}
else {
rb_raise(rb_eArgError, "can not isolate a Proc because it accesses outer variables (%s).",
StringValueCStr(str));
}
}
else {
VM_ASSERT(data.yield);
rb_raise(rb_eArgError, "can not isolate a Proc because it uses `yield'.");
}
}
proc_isolate_env(self, proc);
proc->is_isolated = TRUE;
}
rb_proc_t *proc = (rb_proc_t *)RTYPEDDATA_DATA(self);
proc->is_isolated = TRUE;
return self;
}

View File

@ -418,7 +418,7 @@ struct rb_iseq_constant_body {
char catch_except_p; /* If a frame of this ISeq may catch exception, set TRUE */
bool builtin_inline_p; // This ISeq's builtin func is safe to be inlined by MJIT
char access_outer_variables;
struct rb_id_table *outer_variables;
#if USE_MJIT
/* The following fields are MJIT related info. */
@ -1017,11 +1017,13 @@ typedef enum {
RUBY_SYMBOL_EXPORT_BEGIN
/* node -> iseq */
rb_iseq_t *rb_iseq_new (const rb_ast_body_t *ast, VALUE name, VALUE path, VALUE realpath, const rb_iseq_t *parent, enum iseq_type);
rb_iseq_t *rb_iseq_new_top (const rb_ast_body_t *ast, VALUE name, VALUE path, VALUE realpath, const rb_iseq_t *parent);
rb_iseq_t *rb_iseq_new_main (const rb_ast_body_t *ast, VALUE path, VALUE realpath, const rb_iseq_t *parent);
rb_iseq_t *rb_iseq_new_with_opt(const rb_ast_body_t *ast, VALUE name, VALUE path, VALUE realpath, VALUE first_lineno,
const rb_iseq_t *parent, enum iseq_type, const rb_compile_option_t*);
rb_iseq_t *rb_iseq_new (const rb_ast_body_t *ast, VALUE name, VALUE path, VALUE realpath, const rb_iseq_t *parent, enum iseq_type);
rb_iseq_t *rb_iseq_new_top (const rb_ast_body_t *ast, VALUE name, VALUE path, VALUE realpath, const rb_iseq_t *parent);
rb_iseq_t *rb_iseq_new_main (const rb_ast_body_t *ast, VALUE path, VALUE realpath, const rb_iseq_t *parent);
rb_iseq_t *rb_iseq_new_eval (const rb_ast_body_t *ast, VALUE name, VALUE path, VALUE realpath, VALUE first_lineno, const rb_iseq_t *parent, int isolated_depth);
rb_iseq_t *rb_iseq_new_with_opt(const rb_ast_body_t *ast, VALUE name, VALUE path, VALUE realpath, VALUE first_lineno, const rb_iseq_t *parent, int isolated_depth,
enum iseq_type, const rb_compile_option_t*);
struct iseq_link_anchor;
struct rb_iseq_new_with_callback_callback_func {
VALUE flags;
@ -1156,18 +1158,19 @@ enum {
VM_FRAME_MAGIC_MASK = 0x7fff0001,
/* frame flag */
VM_FRAME_FLAG_PASSED = 0x0010,
VM_FRAME_FLAG_FINISH = 0x0020,
VM_FRAME_FLAG_BMETHOD = 0x0040,
VM_FRAME_FLAG_CFRAME = 0x0080,
VM_FRAME_FLAG_LAMBDA = 0x0100,
VM_FRAME_FLAG_MODIFIED_BLOCK_PARAM = 0x0200,
VM_FRAME_FLAG_CFRAME_KW = 0x0400,
VM_FRAME_FLAG_PASSED = 0x0800,
/* env flag */
VM_ENV_FLAG_LOCAL = 0x0002,
VM_ENV_FLAG_ESCAPED = 0x0004,
VM_ENV_FLAG_WB_REQUIRED = 0x0008
VM_ENV_FLAG_WB_REQUIRED = 0x0008,
VM_ENV_FLAG_ISOLATED = 0x0010,
};
#define VM_ENV_DATA_SIZE ( 3)

View File

@ -1461,6 +1461,23 @@ eval_make_iseq(VALUE src, VALUE fname, int line, const rb_binding_t *bind,
VALUE realpath = Qnil;
rb_iseq_t *iseq = NULL;
rb_ast_t *ast;
int isolated_depth = 0;
{
int depth = 1;
const VALUE *ep = vm_block_ep(base_block);
while (1) {
if (VM_ENV_FLAGS(ep, VM_ENV_FLAG_ISOLATED)) {
isolated_depth = depth;
break;
}
else if (VM_ENV_LOCAL_P(ep)) {
break;
}
ep = VM_ENV_PREV_EP(ep);
depth++;
}
}
if (!fname) {
fname = rb_source_location(&line);
@ -1477,10 +1494,10 @@ eval_make_iseq(VALUE src, VALUE fname, int line, const rb_binding_t *bind,
rb_parser_set_context(parser, parent, FALSE);
ast = rb_parser_compile_string_path(parser, fname, src, line);
if (ast->body.root) {
iseq = rb_iseq_new_with_opt(&ast->body,
parent->body->location.label,
fname, realpath, INT2FIX(line),
parent, ISEQ_TYPE_EVAL, NULL);
iseq = rb_iseq_new_eval(&ast->body,
parent->body->location.label,
fname, realpath, INT2FIX(line),
parent, isolated_depth);
}
rb_ast_dispose(ast);