Skip to content

Commit 7587e92

Browse files
viralpraxisnobu
authored andcommitted
[Bug #21644] compile.c: fix newrange INSN peephole optimization for chilled string
ref: https://bugs.ruby-lang.org/issues/21644 ```shell $ ruby -v -e '("a" || "b").."c"' ruby 3.4.7 (2025-10-08 revision 7a5688e) +PRISM [x86_64-linux] -e:1: warning: possibly useless use of .. in void context -e:1: [BUG] Stack consistency error (sp: 7, bp: 6) ruby 3.4.7 (2025-10-08 revision 7a5688e) +PRISM [x86_64-linux] -- Control frame information ----------------------------------------------- c:0002 p:0013 s:0007 e:000005 EVAL -e:1 [FINISH] c:0001 p:0000 s:0003 E:001920 DUMMY [FINISH] -- Ruby level backtrace information ---------------------------------------- -e:1:in '<main>' -- Threading information --------------------------------------------------- Total ractor count: 1 Ruby thread count for this ractor: 1 -- C level backtrace information ------------------------------------------- ruby/3.4.7/lib/libruby.so.3.4(rb_print_backtrace+0x8) [0x78aa9573c882] /tmp/ruby-build.20251010151551.31019.jR04SY/ruby-3.4.7/vm_dump.c:823 ruby/3.4.7/lib/libruby.so.3.4(rb_vm_bugreport) /tmp/ruby-build.20251010151551.31019.jR04SY/ruby-3.4.7/vm_dump.c:1155 ruby/3.4.7/lib/libruby.so.3.4(rb_bug_without_die_internal+0x6b) [0x78aa9544c62f] /tmp/ruby-build.20251010151551.31019.jR04SY/ruby-3.4.7/error.c:1097 ruby/3.4.7/lib/libruby.so.3.4(rb_bug) /tmp/ruby-build.20251010151551.31019.jR04SY/ruby-3.4.7/error.c:1115 ruby/3.4.7/lib/libruby.so.3.4(vm_stack_consistency_error+0x1f) [0x78aa9544f091] /tmp/ruby-build.20251010151551.31019.jR04SY/ruby-3.4.7/vm_insnhelper.c:6523 ruby/3.4.7/lib/libruby.so.3.4(vm_get_cref) /tmp/ruby-build.20251010151551.31019.jR04SY/ruby-3.4.7/insns.def:1134 ruby/3.4.7/lib/libruby.so.3.4(vm_setclassvariable) /tmp/ruby-build.20251010151551.31019.jR04SY/ruby-3.4.7/vm_insnhelper.c:1630 ruby/3.4.7/lib/libruby.so.3.4(vm_setclassvariable) /tmp/ruby-build.20251010151551.31019.jR04SY/ruby-3.4.7/vm_insnhelper.c:1627 ruby/3.4.7/lib/libruby.so.3.4(vm_exec_core) /tmp/ruby-build.20251010151551.31019.jR04SY/ruby-3.4.7/insns.def:253 ruby/3.4.7/lib/libruby.so.3.4(vm_exec_loop+0xa) [0x78aa95724959] /tmp/ruby-build.20251010151551.31019.jR04SY/ruby-3.4.7/vm.c:2622 ruby/3.4.7/lib/libruby.so.3.4(rb_vm_exec) /tmp/ruby-build.20251010151551.31019.jR04SY/ruby-3.4.7/vm.c:2598 ruby/3.4.7/lib/libruby.so.3.4(rb_ec_exec_node+0xa5) [0x78aa95525695] /tmp/ruby-build.20251010151551.31019.jR04SY/ruby-3.4.7/eval.c:281 ruby/3.4.7/lib/libruby.so.3.4(ruby_run_node+0x83) [0x78aa95529333] /tmp/ruby-build.20251010151551.31019.jR04SY/ruby-3.4.7/eval.c:319 ruby/3.4.7/bin/ruby(rb_main+0x21) [0x59d86f5e0186] ./main.c:43 ruby/3.4.7/bin/ruby(main) ./main.c:68 /lib/x86_64-linux-gnu/libc.so.6(__libc_start_call_main+0x7a) [0x78aa9502a1ca] ../sysdeps/nptl/libc_start_call_main.h:58 /lib/x86_64-linux-gnu/libc.so.6(call_init+0x0) [0x78aa9502a28b] ../csu/libc-start.c:360 /lib/x86_64-linux-gnu/libc.so.6(__libc_start_main_impl) ../csu/libc-start.c:347 /lib/x86_64-linux-gnu/libc.so.6(__libc_start_main) (null):0 [0x59d86f5e01d5] ``` The optimization in question: https://github.com/ruby/ruby/blob/957c832db137e67289e93dfd9fd9e915b1f2fc87/compile.c\#L3453-L3480 Before entering the `newrange` optimization, the iseq looks like this: ``` == disasm: #<ISeq:<compiled>@<compiled>:1 (1,0)-(1,17)> 0000 putchilledstring "a" ( 1)[Li] 0002 dup 0003 branchif 8 0005 pop 0006 putchilledstring "b" 0008 putchilledstring "c" 0010 newrange 0 0012 leave ``` So the optimization constructs a new range using the wrong operands (`"b"` and `"c"` instead of `"a"` and `"c"`). I tried to fix this by checking whether the two previous instructions are labeled.
1 parent 4353187 commit 7587e92

File tree

2 files changed

+22
-1
lines changed

2 files changed

+22
-1
lines changed

compile.c

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3222,6 +3222,25 @@ is_frozen_putstring(INSN *insn, VALUE *op)
32223222
return 0;
32233223
}
32243224

3225+
static int
3226+
insn_has_label_before(LINK_ELEMENT *elem)
3227+
{
3228+
LINK_ELEMENT *prev = elem->prev;
3229+
while (prev) {
3230+
if (prev->type == ISEQ_ELEMENT_LABEL) {
3231+
LABEL *label = (LABEL *)prev;
3232+
if (label->refcnt > 0) {
3233+
return 1;
3234+
}
3235+
}
3236+
else if (prev->type == ISEQ_ELEMENT_INSN) {
3237+
break;
3238+
}
3239+
prev = prev->prev;
3240+
}
3241+
return 0;
3242+
}
3243+
32253244
static int
32263245
optimize_checktype(rb_iseq_t *iseq, INSN *iobj)
32273246
{
@@ -3467,7 +3486,8 @@ iseq_peephole_optimize(rb_iseq_t *iseq, LINK_ELEMENT *list, const int do_tailcal
34673486
if ((end = (INSN *)get_prev_insn(range)) != 0 &&
34683487
is_frozen_putstring(end, &str_end) &&
34693488
(beg = (INSN *)get_prev_insn(end)) != 0 &&
3470-
is_frozen_putstring(beg, &str_beg)) {
3489+
is_frozen_putstring(beg, &str_beg) &&
3490+
!(insn_has_label_before(&beg->link) || insn_has_label_before(&end->link))) {
34713491
int excl = FIX2INT(OPERAND_AT(range, 0));
34723492
VALUE lit_range = rb_range_new(str_beg, str_end, excl);
34733493

test/ruby/test_range.rb

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ def test_range_string
3636
assert_equal(["a"], ("a" ... "b").to_a)
3737
assert_equal(["a", "b"], ("a" .. "b").to_a)
3838
assert_equal([*"a".."z", "aa"], ("a"..).take(27))
39+
assert_equal([*"a".."z"], eval("('a' || 'b')..'z'").to_a)
3940
end
4041

4142
def test_range_numeric_string

0 commit comments

Comments
 (0)