mirror of
https://github.com/ruby/ruby.git
synced 2022-11-09 12:17:21 -05:00
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] git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@66326 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
This commit is contained in:
parent
8e9aa75df1
commit
b91599c48b
2 changed files with 35 additions and 9 deletions
35
compile.c
35
compile.c
|
@ -1298,6 +1298,27 @@ update_catch_except_flags(struct rb_iseq_constant_body *body)
|
|||
}
|
||||
}
|
||||
|
||||
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_ANCHOR *const anchor)
|
|||
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_ANCHOR *const ret, const NODE *const node,
|
|||
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);
|
||||
|
||||
|
|
|
@ -800,4 +800,13 @@ class TestRubyOptimization < Test::Unit::TestCase
|
|||
%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
|
||||
|
|
Loading…
Reference in a new issue