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

ruby-changes:63472

From: Koichi <ko1@a...>
Date: Thu, 29 Oct 2020 23:43:19 +0900 (JST)
Subject: [ruby-changes:63472] 07c03bc309 (master): check isolated Proc more strictly

https://git.ruby-lang.org/ruby.git/commit/?id=07c03bc309

From 07c03bc30984a496558d9e830bc4fb2f8cfb1854 Mon Sep 17 00:00:00 2001
From: Koichi Sasada <ko1@a...>
Date: Fri, 23 Oct 2020 13:27:21 +0900
Subject: 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.

diff --git a/compile.c b/compile.c
index 767e6c4..e0d4bc5 100644
--- a/compile.c
+++ b/compile.c
@@ -1319,9 +1319,12 @@ new_child_iseq(rb_iseq_t *iseq, const NODE *const node, https://github.com/ruby/ruby/blob/trunk/compile.c#L1319
     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,13 +1604,50 @@ iseq_block_param_id_p(const rb_iseq_t *iseq, ID id, int *pidx, int *plevel) https://github.com/ruby/ruby/blob/trunk/compile.c#L1604
 }
 
 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)
+{
+    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++) {
+        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)
 {
-    // set access_outer_variables
     for (int i=0; i<level; i++) {
-        iseq->body->access_outer_variables = TRUE;
         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
@@ -1619,7 +1659,7 @@ iseq_add_getlocal(rb_iseq_t *iseq, LINK_ANCHOR *const seq, int line, int idx, in https://github.com/ruby/ruby/blob/trunk/compile.c#L1659
     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 https://github.com/ruby/ruby/blob/trunk/compile.c#L1671
     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 https://github.com/ruby/ruby/blob/trunk/compile.c#L8255
 	    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:{
diff --git a/iseq.c b/iseq.c
index 85ced12..449d338 100644
--- a/iseq.c
+++ b/iseq.c
@@ -130,6 +130,7 @@ rb_iseq_free(const rb_iseq_t *iseq) https://github.com/ruby/ruby/blob/trunk/iseq.c#L130
 	    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) https://github.com/ruby/ruby/blob/trunk/iseq.c#L576
 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, https://github.com/ruby/ruby/blob/trunk/iseq.c#L603
 
     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 * https://github.com/ruby/ruby/blob/trunk/iseq.c#L794
 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 https://github.com/ruby/ruby/blob/trunk/iseq.c#L810
         }
     }
 
-    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_ https://github.com/ruby/ruby/blob/trunk/iseq.c#L819
 {
     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) https://github.com/ruby/ruby/blob/trunk/iseq.c#L845
 
 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 https://github.com/ruby/ruby/blob/trunk/iseq.c#L861
     }
     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( https://github.com/ruby/ruby/blob/trunk/iseq.c#L880
     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) https://github.com/ruby/ruby/blob/trunk/iseq.c#L993
     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, except (... truncated)

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

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