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/