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

ruby-changes:54105

From: nobu <ko1@a...>
Date: Tue, 11 Dec 2018 13:14:35 +0900 (JST)
Subject: [ruby-changes:54105] nobu:r66326 (trunk): Fix infinite loop by ensure

nobu	2018-12-11 13:14:31 +0900 (Tue, 11 Dec 2018)

  New Revision: 66326

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

  Log:
    Fix infinite loop by ensure
    
    * compile.c (iseq_insert_nop_between_end_and_cont): insert nop so
      that the end of rescue and continuing points are not same, to
      get rid of infinite loop.  [Bug #15385]

  Modified files:
    trunk/compile.c
    trunk/test/ruby/test_optimization.rb
Index: compile.c
===================================================================
--- compile.c	(revision 66325)
+++ compile.c	(revision 66326)
@@ -1298,6 +1298,27 @@ update_catch_except_flags(struct rb_iseq https://github.com/ruby/ruby/blob/trunk/compile.c#L1298
     }
 }
 
+static void
+iseq_insert_nop_between_end_and_cont(rb_iseq_t *iseq)
+{
+    VALUE catch_table_ary = ISEQ_COMPILE_DATA(iseq)->catch_table_ary;
+    unsigned int i, tlen = (unsigned int)RARRAY_LEN(catch_table_ary);
+    const VALUE *tptr = RARRAY_CONST_PTR_TRANSIENT(catch_table_ary);
+    for (i = 0; i < tlen; i++) {
+        const VALUE *ptr = RARRAY_CONST_PTR_TRANSIENT(tptr[i]);
+        LINK_ELEMENT *end = (LINK_ELEMENT *)(ptr[2] & ~1);
+        LINK_ELEMENT *cont = (LINK_ELEMENT *)(ptr[4] & ~1);
+        LINK_ELEMENT *e;
+        for (e = end; e && (IS_LABEL(e) || IS_TRACE(e)); e = e->next) {
+            if (e == cont) {
+                INSN *nop = new_insn_core(iseq, 0, BIN(nop), 0, 0);
+                ELEM_INSERT_NEXT(end, &nop->link);
+                break;
+            }
+        }
+    }
+}
+
 static int
 iseq_setup_insn(rb_iseq_t *iseq, LINK_ANCHOR *const anchor)
 {
@@ -1329,6 +1350,9 @@ iseq_setup_insn(rb_iseq_t *iseq, LINK_AN https://github.com/ruby/ruby/blob/trunk/compile.c#L1350
 	    dump_disasm_list(FIRST_ELEMENT(anchor));
     }
 
+    debugs("[compile step 3.4 (iseq_insert_nop_between_end_and_cont)]\n");
+    iseq_insert_nop_between_end_and_cont(iseq);
+
     return COMPILE_OK;
 }
 
@@ -5763,15 +5787,8 @@ compile_ensure(rb_iseq_t *iseq, LINK_ANC https://github.com/ruby/ruby/blob/trunk/compile.c#L5787
     ADD_LABEL(ret, lstart);
     CHECK(COMPILE_(ret, "ensure head", node->nd_head, (popped | last_leave)));
     ADD_LABEL(ret, lend);
-    if (LIST_INSN_SIZE_ZERO(ensr)) {
-	ADD_INSN(ret, line, nop);
-    }
-    else {
-	ADD_SEQ(ret, ensr);
-	if (!popped && last_leave) {
-	    ADD_INSN(ret, line, putnil);
-	}
-    }
+    ADD_SEQ(ret, ensr);
+    if (!popped && last_leave) ADD_INSN(ret, line, putnil);
     ADD_LABEL(ret, lcont);
     if (last_leave) ADD_INSN(ret, line, pop);
 
Index: test/ruby/test_optimization.rb
===================================================================
--- test/ruby/test_optimization.rb	(revision 66325)
+++ test/ruby/test_optimization.rb	(revision 66326)
@@ -800,4 +800,13 @@ class TestRubyOptimization < Test::Unit: https://github.com/ruby/ruby/blob/trunk/test/ruby/test_optimization.rb#L800
     %w(1) || 2 while (i += 1) < 100
     assert_equal(100, i)
   end
+
+  def test_optimized_empty_ensure
+    assert_separately([], "#{<<~"begin;"}\n#{<<~'end;'}", timeout: 1)
+    begin;
+      assert_raise(RuntimeError) {
+        begin raise ensure nil if nil end
+      }
+    end;
+  end
 end

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

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