Project

General

Profile

Actions

Bug #21644

closed

Stack consistency error for the `newrange` INSN peephole optimization with chilled string

Bug #21644: Stack consistency error for the `newrange` INSN peephole optimization with chilled string

Added by viralpraxis (Iaroslav Kurbatov) 1 day ago. Updated about 23 hours ago.

Status:
Closed
Assignee:
-
Target version:
-
ruby -v:
ruby 3.4.7 (2025-10-08 revision 7a5688e2a2) +PRISM [x86_64-linux]
[ruby-core:<unknown>]

Description

PR:https://github.com/ruby/ruby/pull/14879

Confirmed on every version since 3.4.

$ ruby -v -e '("a" || "b").."c"'
ruby 3.4.7 (2025-10-08 revision 7a5688e2a2) +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 7a5688e2a2) +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 this 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").

Also, I'm wondering why chilled strings are not ||-peephole-optimized?

ruby --dump insn -ve '"a" || "b"'
ruby 3.5.0dev (2025-10-19T14:22:25Z master 957c832db1) +PRISM [x86_64-linux]
== disasm: #<ISeq:<main>@-e:1 (1,0)-(1,10)>
0000 putchilledstring                       "a"                       (   1)[Li]
0002 dup
0003 branchif                               8
0005 pop
0006 putchilledstring                       "b"
0008 leave
ruby --enable-frozen-string-literal --dump insn -ve '"a" || "b"'
ruby 3.5.0dev (2025-10-19T14:22:25Z master 957c832db1) +PRISM [x86_64-linux]
== disasm: #<ISeq:<main>@-e:1 (1,0)-(1,10)>
0000 putobject                              "a"                       (   1)[Li]
0002 leave
ruby --disable-frozen-string-literal --dump insn -ve '"a" || "b"'
ruby 3.5.0dev (2025-10-19T14:22:25Z master 957c832db1) +PRISM [x86_64-linux]
== disasm: #<ISeq:<main>@-e:1 (1,0)-(1,10)>
0000 putstring                              "a"                       (   1)[Li]
0002 leave

Updated by nobu (Nobuyoshi Nakada) about 24 hours ago Actions #1

  • Backport changed from 3.2: UNKNOWN, 3.3: UNKNOWN, 3.4: UNKNOWN to 3.2: DONTNEED, 3.3: DONTNEED, 3.4: REQUIRED

Updated by viralpraxis (Iaroslav Kurbatov) about 23 hours ago Actions #2

  • Status changed from Open to Closed

Applied in changeset git|7587e92910e7604a4c66f2b804bfa2076339c6ff.


[Bug #21644] compile.c: fix newrange INSN peephole optimization for chilled string

ref: https://bugs.ruby-lang.org/issues/21644

$ ruby -v -e '("a" || "b").."c"'
ruby 3.4.7 (2025-10-08 revision 7a5688e2a2) +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 7a5688e2a2) +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.

Actions

Also available in: PDF Atom