Project

General

Profile

Actions

Bug #21516

open

Segfault in String#succ! on 32-bit i686

Added by leahneukirchen (Leah Neukirchen) about 18 hours ago. Updated about 14 hours ago.

Status:
Open
Assignee:
-
Target version:
-
[ruby-core:122798]

Description

I noticed segfaults in the test suite of Ruby 3.4.5, related to String#succ!

A very easy reproducer is:

./miniruby -e 'puts "ZZZZ999".succ!'

$ ./miniruby -e 'puts "ZZZZ999".succ!'
-e:1: [BUG] Segmentation fault at 0x9e968041
ruby 3.4.5 (2025-07-16 revision 20cda200d3) +PRISM [x86_64-linux-x32]

-- Control frame information -----------------------------------------------
c:0003 p:---- s:0011 e:000010 CFUNC :succ!
c:0002 p:0005 s:0007 e:000005 EVAL -e:1 [FINISH]
c:0001 p:0000 s:0003 E:0017b8 DUMMY [FINISH]

-- Ruby level backtrace information ----------------------------------------
-e:1:in ''
-e:1:in 'succ!'

-- Threading information ---------------------------------------------------
Total ractor count: 1
Ruby thread count for this ractor: 1

-- Machine register context ------------------------------------------------
GS: 0x00000063 FS: 0x00000000 ES: 0x0000002b DS: 0x0000002b EDI: 0x9e968049
ESI: 0x9e968041 EBP: 0x5896c1a0 ESP: 0xff97d638 EBX: 0x9e968046 EDX: 0x9e968049
ECX: 0x5896c1a0 EAX: 0x9e968041 TRA: 0x0000000e ERR: 0x00000004 EIP: 0x5681ea07
CS: 0x00000023 EFL: 0x00010293 UES: 0xff97d638 SS: 0x0000002b

-- C level backtrace information -------------------------------------------
/builddir/ruby/ruby/miniruby(rb_print_backtrace+0x14) [0x568ae631] /builddir/ruby/ruby/vm_dump.c:823
/builddir/ruby/ruby/miniruby(rb_vm_bugreport) /builddir/ruby/ruby/vm_dump.c:1155
/builddir/ruby/ruby/miniruby(rb_bug_for_fatal_signal+0x86) [0x566e4ee6] /builddir/ruby/ruby/error.c:1130
/builddir/ruby/ruby/miniruby(sigsegv+0x4f) [0x5680e98f] /builddir/ruby/ruby/signal.c:934
linux-gate.so.1(_kernel_rt_sigreturn+0x0) [0xf7f475a0]
/builddir/ruby/ruby/miniruby(search_nonascii+0x17) [0x5681ea07] /builddir/ruby/ruby/string.c:728
/builddir/ruby/ruby/miniruby(coderange_scan+0x59) [0x56821d09] /builddir/ruby/ruby/string.c:767
/builddir/ruby/ruby/miniruby(rbimpl_fl_unset_raw_raw+0x0) [0x56824715] /builddir/ruby/ruby/string.c:895
/builddir/ruby/ruby/miniruby(RB_FL_UNSET_RAW) ./include/ruby/internal/fl_type.h:669
/builddir/ruby/ruby/miniruby(RB_ENC_CODERANGE_SET) ./include/ruby/internal/encoding/coderange.h:131
/builddir/ruby/ruby/miniruby(rb_enc_str_coderange) /builddir/ruby/ruby/string.c:911
/builddir/ruby/ruby/miniruby(str_succ+0x69c) [0x5682545c] /builddir/ruby/ruby/string.c:5364
/builddir/ruby/ruby/miniruby(rb_str_succ_bang+0x15) [0x56829f85] /builddir/ruby/ruby/string.c:5380
/builddir/ruby/ruby/miniruby(vm_call_cfunc_with_frame
+0x106) [0x568860e6] /builddir/ruby/ruby/vm_insnhelper.c:3794
/builddir/ruby/ruby/miniruby(vm_call_method_each_type+0x76) [0x56894636] /builddir/ruby/ruby/vm_insnhelper.c:4772
/builddir/ruby/ruby/miniruby(vm_sendish+0xa2) [0x5689fecb] /builddir/ruby/ruby/vm_insnhelper.c:5961
/builddir/ruby/ruby/miniruby(vm_exec_core) /builddir/ruby/ruby/insns.def:898
/builddir/ruby/ruby/miniruby(vm_exec_loop+0x38) [0x56893d68] /builddir/ruby/ruby/vm.c:2622
/builddir/ruby/ruby/miniruby(rb_vm_exec) /builddir/ruby/ruby/vm.c:2598
/builddir/ruby/ruby/miniruby(rb_ec_exec_node+0x7f) [0x566eb0ef] /builddir/ruby/ruby/eval.c:281
/builddir/ruby/ruby/miniruby(ruby_run_node+0x58) [0x566ee558] /builddir/ruby/ruby/eval.c:319
/builddir/ruby/ruby/miniruby(main+0x70) [0x56648460] ./main.c:43

-- Other runtime information -----------------------------------------------

  • Loaded script: -e

  • Loaded features:

    0 enumerator.so
    1 thread.rb
    2 fiber.so
    3 rational.so
    4 complex.so
    5 ruby2_keywords.rb

  • Process memory map:

56622000-56642000 r--p 00000000 fe:02 9210459 /builddir/ruby/ruby/miniruby
56642000-56941000 r-xp 00020000 fe:02 9210459 /builddir/ruby/ruby/miniruby
56941000-56b4c000 r--p 0031f000 fe:02 9210459 /builddir/ruby/ruby/miniruby
56b4c000-56b54000 r--p 0052a000 fe:02 9210459 /builddir/ruby/ruby/miniruby
56b54000-56b55000 rw-p 00532000 fe:02 9210459 /builddir/ruby/ruby/miniruby
56b55000-56b5e000 rw-p 00000000 00:00 0
58967000-58abb000 rw-p 00000000 00:00 0 [heap]
f43b8000-f5a48000 r--s 00000000 fe:02 9210459 /builddir/ruby/ruby/miniruby
f5a48000-f5a4b000 r--p 00000000 fe:02 11307369 /usr/lib/libgcc_s.so.1
f5a4b000-f5a79000 r-xp 00003000 fe:02 11307369 /usr/lib/libgcc_s.so.1
f5a79000-f5a7e000 r--p 00031000 fe:02 11307369 /usr/lib/libgcc_s.so.1
f5a7e000-f5a7f000 r--p 00035000 fe:02 11307369 /usr/lib/libgcc_s.so.1
f5a7f000-f5a80000 rw-p 00036000 fe:02 11307369 /usr/lib/libgcc_s.so.1
f5a80000-f5ab0000 rw-p 00000000 00:00 0 [anon:Ruby:GC:default:heap_page_body_allocate]
f5abf000-f5ac0000 ---p 00000000 00:00 0 [anon:Ruby:fiber_pool_allocate_memory]
f5ac0000-f5b11000 rw-p 00000000 00:00 0 [anon:Ruby:fiber_pool_allocate_memory]
f5b11000-f5b12000 ---p 00000000 00:00 0 [anon:Ruby:fiber_pool_allocate_memory]
f5b12000-f5b63000 rw-p 00000000 00:00 0 [anon:Ruby:fiber_pool_allocate_memory]
f5b63000-f5b64000 ---p 00000000 00:00 0 [anon:Ruby:fiber_pool_allocate_memory]
f5b64000-f5bb5000 rw-p 00000000 00:00 0 [anon:Ruby:fiber_pool_allocate_memory]
f5bb5000-f5bb6000 ---p 00000000 00:00 0 [anon:Ruby:fiber_pool_allocate_memory]
f5bb6000-f5c07000 rw-p 00000000 00:00 0 [anon:Ruby:fiber_pool_allocate_memory]
f5c07000-f5c08000 ---p 00000000 00:00 0 [anon:Ruby:fiber_pool_allocate_memory]
f5c08000-f5c59000 rw-p 00000000 00:00 0 [anon:Ruby:fiber_pool_allocate_memory]
f5c59000-f5c5a000 ---p 00000000 00:00 0 [anon:Ruby:fiber_pool_allocate_memory]
f5c5a000-f5cab000 rw-p 00000000 00:00 0 [anon:Ruby:fiber_pool_allocate_memory]
f5cab000-f5cac000 ---p 00000000 00:00 0 [anon:Ruby:fiber_pool_allocate_memory]
f5cac000-f5cfd000 rw-p 00000000 00:00 0 [anon:Ruby:fiber_pool_allocate_memory]
f5cfd000-f5cfe000 ---p 00000000 00:00 0 [anon:Ruby:fiber_pool_allocate_memory]
f5cfe000-f5d4f000 rw-p 00000000 00:00 0 [anon:Ruby:fiber_pool_allocate_memory]
f5d4f000-f5d50000 ---p 00000000 00:00 0
f5d50000-f6550000 rw-p 00000000 00:00 0
f6550000-f6590000 rw-p 00000000 00:00 0 [anon:Ruby:GC:default:heap_page_body_allocate]
f659f000-f759f000 rw-p 00000000 00:00 0 [anon:Ruby:Init_default_shapes:shape_cache]
f759f000-f765f000 rw-p 00000000 00:00 0 [anon:Ruby:Init_default_shapes:shape_list]
f765f000-f7690000 rw-p 00000000 00:00 0
f7690000-f76a0000 rw-p 00000000 00:00 0 [anon:Ruby:GC:default:heap_page_body_allocate]
f76a9000-f772a000 rw-p 00000000 00:00 0
f772a000-f79a4000 r--p 00074000 fe:02 11307480 /usr/lib/locale/locale-archive
f79a4000-f7ba4000 r--p 00000000 fe:02 11307480 /usr/lib/locale/locale-archive
f7ba4000-f7ba6000 rw-p 00000000 00:00 0
f7ba6000-f7bc9000 r--p 00000000 fe:02 11307064 /usr/lib/libc.so.6
f7bc9000-f7d69000 r-xp 00023000 fe:02 11307064 /usr/lib/libc.so.6
f7d69000-f7dc5000 r--p 001c3000 fe:02 11307064 /usr/lib/libc.so.6
f7dc5000-f7dc7000 r--p 0021f000 fe:02 11307064 /usr/lib/libc.so.6
f7dc7000-f7dc8000 rw-p 00221000 fe:02 11307064 /usr/lib/libc.so.6
f7dc8000-f7dd2000 rw-p 00000000 00:00 0
f7dd2000-f7de0000 r--p 00000000 fe:02 11307059 /usr/lib/libm.so.6
f7de0000-f7ead000 r-xp 0000e000 fe:02 11307059 /usr/lib/libm.so.6
f7ead000-f7edf000 r--p 000db000 fe:02 11307059 /usr/lib/libm.so.6
f7edf000-f7ee0000 r--p 0010c000 fe:02 11307059 /usr/lib/libm.so.6
f7ee0000-f7ee1000 rw-p 0010d000 fe:02 11307059 /usr/lib/libm.so.6
f7ee1000-f7ee2000 r--p 00000000 fe:02 11307767 /usr/lib/libcrypt.so.2.0.0
f7ee2000-f7efe000 r-xp 00001000 fe:02 11307767 /usr/lib/libcrypt.so.2.0.0
f7efe000-f7f18000 r--p 0001d000 fe:02 11307767 /usr/lib/libcrypt.so.2.0.0
f7f18000-f7f19000 r--p 00036000 fe:02 11307767 /usr/lib/libcrypt.so.2.0.0
f7f19000-f7f1a000 rw-p 00037000 fe:02 11307767 /usr/lib/libcrypt.so.2.0.0
f7f1a000-f7f22000 rw-p 00000000 00:00 0
f7f22000-f7f24000 r--p 00000000 fe:02 11307365 /usr/lib/libz.so.1.3.1
f7f24000-f7f34000 r-xp 00002000 fe:02 11307365 /usr/lib/libz.so.1.3.1
f7f34000-f7f3a000 r--p 00012000 fe:02 11307365 /usr/lib/libz.so.1.3.1
f7f3a000-f7f3b000 r--p 00017000 fe:02 11307365 /usr/lib/libz.so.1.3.1
f7f3b000-f7f3c000 rw-p 00018000 fe:02 11307365 /usr/lib/libz.so.1.3.1
f7f41000-f7f43000 rw-p 00000000 00:00 0
f7f43000-f7f45000 r--p 00000000 00:00 0 [vvar]
f7f45000-f7f47000 r--p 00000000 00:00 0 [vvar_vclock]
f7f47000-f7f49000 r-xp 00000000 00:00 0 [vdso]
f7f49000-f7f4a000 r--p 00000000 fe:02 11307070 /usr/lib/ld-linux.so.2
f7f4a000-f7f72000 r-xp 00001000 fe:02 11307070 /usr/lib/ld-linux.so.2
f7f72000-f7f7d000 r--p 00029000 fe:02 11307070 /usr/lib/ld-linux.so.2
f7f7d000-f7f7f000 r--p 00034000 fe:02 11307070 /usr/lib/ld-linux.so.2
f7f7f000-f7f80000 rw-p 00036000 fe:02 11307070 /usr/lib/ld-linux.so.2
ff95d000-ff97e000 rw-p 00000000 00:00 0 [stack]

Segmentation fault

Backtrace in gdb:

Thread 1 "miniruby" received signal SIGSEGV, Segmentation fault.
search_nonascii (p=, e=0xb3b91049 <error: Cannot access memory at address 0xb3b91049>) at string.c:729
729 if (*s & NONASCII_MASK) {
(gdb) bt
#0 search_nonascii (p=, e=0xb3b91049 <error: Cannot access memory at address 0xb3b91049>) at string.c:729
#1 0x56754d09 in coderange_scan (p=0xb3b91041 <error: Cannot access memory at address 0xb3b91041>, len=8, enc=0x56a961a0)
at string.c:767
#2 0x56757715 in enc_coderange_scan (str=4122077840, enc=) at ./include/ruby/internal/core/rstring.h:430
#3 rb_enc_str_coderange (str=4122077840) at string.c:910
#4 0x5675845c in str_succ (str=str@entry=4122077840) at string.c:5364
#5 0x5675cf85 in rb_str_succ_bang (str=4122077840) at string.c:5380
#6 0x567b90e6 in vm_call_cfunc_with_frame_ (ec=0x56a9598c, reg_cfp=0xf77a6fd8, calling=, argc=0, argv=0xf7727030,
stack_bottom=0xf772702c) at /builddir/ruby/ruby/vm_insnhelper.c:3794
#7 0x567c7636 in vm_call_method_each_type (ec=0x56a9598c, cfp=0xf77a6fd8, calling=0xffffd9e8)
at /builddir/ruby/ruby/vm_insnhelper.c:4772
#8 0x567d2ecb in vm_sendish (ec=, reg_cfp=, cd=, block_handler=,
method_explorer=) at /builddir/ruby/ruby/vm_callinfo.h:415
#9 vm_exec_core (ec=0xb3b91041, ec@entry=0x56a9598c) at /builddir/ruby/ruby/insns.def:898
#10 0x567c6d68 in vm_exec_loop (ec=, state=, tag=, result=10) at vm.c:2622
#11 rb_vm_exec (ec=0x56a9598c) at vm.c:2598
#12 0x5661e0ef in rb_ec_exec_node (ec=ec@entry=0x56a9598c, n=n@entry=0xf5b1eaf4) at eval.c:281
#13 0x56621558 in ruby_run_node (n=0xf5b1eaf4) at eval.c:319
#14 0x5657b460 in rb_main (argc=5, argv=0xffffdc34) at ./main.c:43
#15 main (argc=, argv=) at ./main.c:68

I can trigger this with "./configure CFLAGS="-O2 -g" The -O2 is important. With -flto=auto it goes away, with -O0 or -O3 too.
I use gcc (GCC) 14.2.1 20250405 on Void Linux with glibc 2.41. On 64-bit x86_64 it works fine with same versions.

I have bisected the issue to https://github.com/ruby/ruby/commit/14d154076876
but I don't see how this can introduce the bug. I assume it's some undefined behavior that is potentially triggered.
(However reverting that patch works...)

I think the behavior is related to the embedded string being expanded into a proper string, but my internal-fu isn't good enough.

I hope this helps to debug the issue.

Updated by leahneukirchen (Leah Neukirchen) about 14 hours ago

It seems RESIZE_CAPA_TERM is miscompiled, so this may not be a Ruby issue but a compiler problem.

At the end of the if(STR_EMBED_P(str)) block, RSTRING_PTR(str) still points into the string object and not to the new heap-allocated string.

Printing the address of str after RESIZE_CAPA(str, slen + carry_len); seems to work around it, could be some aliasing issue.

Actions

Also available in: Atom PDF

Like0
Like0