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

ruby-changes:46929

From: ko1 <ko1@a...>
Date: Thu, 8 Jun 2017 13:13:59 +0900 (JST)
Subject: [ruby-changes:46929] ko1:r59043 (trunk): check break target correctly.

ko1	2017-06-08 13:13:51 +0900 (Thu, 08 Jun 2017)

  New Revision: 59043

  https://svn.ruby-lang.org/cgi-bin/viewvc.cgi?view=revision&revision=59043

  Log:
    check break target correctly.
    
    * compile.c (iseq_compile_each0): save target child_iseq in the catch-table
      for break. This iseq is not for continuation, but for search key at
      vm_throw_start().
    
    * vm_insnhelper.c (vm_throw_start): check saved iseq first.
    
    * iseq.h: add comment for it.
    
    * test/ruby/test_iterator.rb (test_ljump): add a test for the issue:
        def call b; b.call; end
        call(Proc.new{break}){} #=> (1) should raise LocalJumpError
        call(Proc.new{break})   #=> (2) shoudd raies LocalJumpError, too.
      but (1) doesn't raise LocalJumpError.
    
      This issue is reported by Matz.

  Modified files:
    trunk/compile.c
    trunk/iseq.h
    trunk/test/ruby/test_iterator.rb
    trunk/vm_insnhelper.c
Index: vm_insnhelper.c
===================================================================
--- vm_insnhelper.c	(revision 59042)
+++ vm_insnhelper.c	(revision 59043)
@@ -1090,7 +1090,9 @@ vm_throw_start(rb_thread_t *const th, rb https://github.com/ruby/ruby/blob/trunk/vm_insnhelper.c#L1090
 		    for (i=0; i<ct_size; i++) {
 			const struct iseq_catch_table_entry * const entry = &ct->entries[i];
 
-			if (entry->type == CATCH_TYPE_BREAK && entry->start < epc && entry->end >= epc) {
+			if (entry->type == CATCH_TYPE_BREAK &&
+			    entry->iseq == base_iseq &&
+			    entry->start < epc && entry->end >= epc) {
 			    if (entry->cont == epc) { /* found! */
 				is_orphan = 0;
 			    }
Index: compile.c
===================================================================
--- compile.c	(revision 59042)
+++ compile.c	(revision 59043)
@@ -4399,17 +4399,20 @@ iseq_compile_each0(rb_iseq_t *iseq, LINK https://github.com/ruby/ruby/blob/trunk/compile.c#L4399
 	const rb_iseq_t *prevblock = ISEQ_COMPILE_DATA(iseq)->current_block;
 	LABEL *retry_label = NEW_LABEL(line);
 	LABEL *retry_end_l = NEW_LABEL(line);
+	const rb_iseq_t *child_iseq;
 
 	ADD_LABEL(ret, retry_label);
 	if (nd_type(node) == NODE_FOR) {
 	    CHECK(COMPILE(ret, "iter caller (for)", node->nd_iter));
 
-	    ISEQ_COMPILE_DATA(iseq)->current_block = NEW_CHILD_ISEQ(node->nd_body, make_name_for_block(iseq),
+	    ISEQ_COMPILE_DATA(iseq)->current_block = child_iseq =
+	      NEW_CHILD_ISEQ(node->nd_body, make_name_for_block(iseq),
 							       ISEQ_TYPE_BLOCK, line);
-	    ADD_SEND_WITH_BLOCK(ret, line, idEach, INT2FIX(0), ISEQ_COMPILE_DATA(iseq)->current_block);
+	    ADD_SEND_WITH_BLOCK(ret, line, idEach, INT2FIX(0), child_iseq);
 	}
 	else {
-	    ISEQ_COMPILE_DATA(iseq)->current_block = NEW_CHILD_ISEQ(node->nd_body, make_name_for_block(iseq),
+	    ISEQ_COMPILE_DATA(iseq)->current_block = child_iseq =
+	      NEW_CHILD_ISEQ(node->nd_body, make_name_for_block(iseq),
 							       ISEQ_TYPE_BLOCK, line);
 	    CHECK(COMPILE(ret, "iter caller", node->nd_iter));
 	}
@@ -4421,7 +4424,7 @@ iseq_compile_each0(rb_iseq_t *iseq, LINK https://github.com/ruby/ruby/blob/trunk/compile.c#L4424
 
 	ISEQ_COMPILE_DATA(iseq)->current_block = prevblock;
 
-	ADD_CATCH_ENTRY(CATCH_TYPE_BREAK, retry_label, retry_end_l, NULL, retry_end_l);
+	ADD_CATCH_ENTRY(CATCH_TYPE_BREAK, retry_label, retry_end_l, child_iseq, retry_end_l);
 
 	break;
       }
Index: test/ruby/test_iterator.rb
===================================================================
--- test/ruby/test_iterator.rb	(revision 59042)
+++ test/ruby/test_iterator.rb	(revision 59043)
@@ -279,6 +279,9 @@ class TestIterator < Test::Unit::TestCas https://github.com/ruby/ruby/blob/trunk/test/ruby/test_iterator.rb#L279
   def proc_call(&b)
     b.call
   end
+  def proc_call2(b)
+    b.call
+  end
   def proc_yield()
     yield
   end
@@ -300,6 +303,7 @@ class TestIterator < Test::Unit::TestCas https://github.com/ruby/ruby/blob/trunk/test/ruby/test_iterator.rb#L303
 
   def test_ljump
     assert_raise(LocalJumpError) {get_block{break}.call}
+    assert_raise(LocalJumpError) {proc_call2(get_block{break}){}}
 
     # cannot use assert_nothing_raised due to passing block.
     begin
Index: iseq.h
===================================================================
--- iseq.h	(revision 59042)
+++ iseq.h	(revision 59043)
@@ -151,7 +151,21 @@ struct iseq_catch_table_entry { https://github.com/ruby/ruby/blob/trunk/iseq.h#L151
 	CATCH_TYPE_REDO   = INT2FIX(5),
 	CATCH_TYPE_NEXT   = INT2FIX(6)
     } type;
+    
+    /*
+     * iseq type:
+     *   CATCH_TYPE_RESCUE, CATCH_TYPE_ENSURE:
+     *     use iseq as continuation.
+     *
+     *   CATCH_TYPE_BREAK (iter):
+     *     use iseq as key.
+     *
+     *   CATCH_TYPE_BREAK (while), CATCH_TYPE_RETRY,
+     *   CATCH_TYPE_REDO, CATCH_TYPE_NEXT:
+     *     NULL.
+     */
     const rb_iseq_t *iseq;
+
     unsigned int start;
     unsigned int end;
     unsigned int cont;

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

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