Skip to content

Commit 7d8a415

Browse files
committed
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. git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@59043 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
1 parent 0318de2 commit 7d8a415

File tree

4 files changed

+28
-5
lines changed

4 files changed

+28
-5
lines changed

compile.c

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4399,17 +4399,20 @@ iseq_compile_each0(rb_iseq_t *iseq, LINK_ANCHOR *const ret, NODE *node, int popp
43994399
const rb_iseq_t *prevblock = ISEQ_COMPILE_DATA(iseq)->current_block;
44004400
LABEL *retry_label = NEW_LABEL(line);
44014401
LABEL *retry_end_l = NEW_LABEL(line);
4402+
const rb_iseq_t *child_iseq;
44024403

44034404
ADD_LABEL(ret, retry_label);
44044405
if (nd_type(node) == NODE_FOR) {
44054406
CHECK(COMPILE(ret, "iter caller (for)", node->nd_iter));
44064407

4407-
ISEQ_COMPILE_DATA(iseq)->current_block = NEW_CHILD_ISEQ(node->nd_body, make_name_for_block(iseq),
4408+
ISEQ_COMPILE_DATA(iseq)->current_block = child_iseq =
4409+
NEW_CHILD_ISEQ(node->nd_body, make_name_for_block(iseq),
44084410
ISEQ_TYPE_BLOCK, line);
4409-
ADD_SEND_WITH_BLOCK(ret, line, idEach, INT2FIX(0), ISEQ_COMPILE_DATA(iseq)->current_block);
4411+
ADD_SEND_WITH_BLOCK(ret, line, idEach, INT2FIX(0), child_iseq);
44104412
}
44114413
else {
4412-
ISEQ_COMPILE_DATA(iseq)->current_block = NEW_CHILD_ISEQ(node->nd_body, make_name_for_block(iseq),
4414+
ISEQ_COMPILE_DATA(iseq)->current_block = child_iseq =
4415+
NEW_CHILD_ISEQ(node->nd_body, make_name_for_block(iseq),
44134416
ISEQ_TYPE_BLOCK, line);
44144417
CHECK(COMPILE(ret, "iter caller", node->nd_iter));
44154418
}
@@ -4421,7 +4424,7 @@ iseq_compile_each0(rb_iseq_t *iseq, LINK_ANCHOR *const ret, NODE *node, int popp
44214424

44224425
ISEQ_COMPILE_DATA(iseq)->current_block = prevblock;
44234426

4424-
ADD_CATCH_ENTRY(CATCH_TYPE_BREAK, retry_label, retry_end_l, NULL, retry_end_l);
4427+
ADD_CATCH_ENTRY(CATCH_TYPE_BREAK, retry_label, retry_end_l, child_iseq, retry_end_l);
44254428

44264429
break;
44274430
}

iseq.h

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -151,7 +151,21 @@ struct iseq_catch_table_entry {
151151
CATCH_TYPE_REDO = INT2FIX(5),
152152
CATCH_TYPE_NEXT = INT2FIX(6)
153153
} type;
154+
155+
/*
156+
* iseq type:
157+
* CATCH_TYPE_RESCUE, CATCH_TYPE_ENSURE:
158+
* use iseq as continuation.
159+
*
160+
* CATCH_TYPE_BREAK (iter):
161+
* use iseq as key.
162+
*
163+
* CATCH_TYPE_BREAK (while), CATCH_TYPE_RETRY,
164+
* CATCH_TYPE_REDO, CATCH_TYPE_NEXT:
165+
* NULL.
166+
*/
154167
const rb_iseq_t *iseq;
168+
155169
unsigned int start;
156170
unsigned int end;
157171
unsigned int cont;

test/ruby/test_iterator.rb

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -279,6 +279,9 @@ def test_return2
279279
def proc_call(&b)
280280
b.call
281281
end
282+
def proc_call2(b)
283+
b.call
284+
end
282285
def proc_yield()
283286
yield
284287
end
@@ -300,6 +303,7 @@ def test_proc_return2
300303

301304
def test_ljump
302305
assert_raise(LocalJumpError) {get_block{break}.call}
306+
assert_raise(LocalJumpError) {proc_call2(get_block{break}){}}
303307

304308
# cannot use assert_nothing_raised due to passing block.
305309
begin

vm_insnhelper.c

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1090,7 +1090,9 @@ vm_throw_start(rb_thread_t *const th, rb_control_frame_t *const reg_cfp, enum ru
10901090
for (i=0; i<ct_size; i++) {
10911091
const struct iseq_catch_table_entry * const entry = &ct->entries[i];
10921092

1093-
if (entry->type == CATCH_TYPE_BREAK && entry->start < epc && entry->end >= epc) {
1093+
if (entry->type == CATCH_TYPE_BREAK &&
1094+
entry->iseq == base_iseq &&
1095+
entry->start < epc && entry->end >= epc) {
10941096
if (entry->cont == epc) { /* found! */
10951097
is_orphan = 0;
10961098
}

0 commit comments

Comments
 (0)