Skip to content

Conversation

@tekknolagi
Copy link
Owner

No description provided.

@tekknolagi
Copy link
Owner Author

..........oops

@tekknolagi tekknolagi closed this May 23, 2025
tekknolagi pushed a commit that referenced this pull request Jun 12, 2025
In commit d42b9ff, an optimization was introduced that can speed up
Regexp#match by 15% when it matches with strings of different encodings.
This optimization, however, does not work across ractors. To fix this,
we only use the optimization if no ractors have been started. In the
future, we could use atomics for the reference counting if we find it's
needed and if it's more performant.

The backtrace of the misbehaving native thread:

```
  * frame #0: 0x0000000189c94388 libsystem_kernel.dylib`__pthread_kill + 8
    frame #1: 0x0000000189ccd88c libsystem_pthread.dylib`pthread_kill + 296
    frame #2: 0x0000000189bd6c60 libsystem_c.dylib`abort + 124
    frame #3: 0x0000000189adb174 libsystem_malloc.dylib`malloc_vreport + 892
    frame Shopify#4: 0x0000000189adec90 libsystem_malloc.dylib`malloc_report + 64
    frame Shopify#5: 0x0000000189ae321c libsystem_malloc.dylib`___BUG_IN_CLIENT_OF_LIBMALLOC_POINTER_BEING_FREED_WAS_NOT_ALLOCATED + 32
    frame Shopify#6: 0x00000001001c3be4 ruby`onig_free_body(reg=0x000000012d84b660) at regcomp.c:5663:5
    frame Shopify#7: 0x00000001001ba828 ruby`rb_reg_prepare_re(re=4748462304, str=4748451168) at re.c:1680:13
    frame Shopify#8: 0x00000001001bac58 ruby`rb_reg_onig_match(re=4748462304, str=4748451168, match=(ruby`reg_onig_search [inlined] rbimpl_RB_TYPE_P_fastpath at value_type.h:349:14
ruby`reg_onig_search [inlined] rbimpl_rstring_getmem at rstring.h:391:5
ruby`reg_onig_search at re.c:1781:5), args=0x000000013824b168, regs=0x000000013824b150) at re.c:1708:20
    frame Shopify#9: 0x00000001001baefc ruby`rb_reg_search_set_match(re=4748462304, str=4748451168, pos=<unavailable>, reverse=0, set_backref_str=1, set_match=0x0000000000000000) at re.c:1809:27
    frame Shopify#10: 0x00000001001bae80 ruby`rb_reg_search0(re=<unavailable>, str=<unavailable>, pos=<unavailable>, reverse=<unavailable>, set_backref_str=<unavailable>, match=<unavailable>) at re.c:1861:12 [artificial]
    frame Shopify#11: 0x0000000100230b90 ruby`rb_pat_search0(pat=<unavailable>, str=<unavailable>, pos=<unavailable>, set_backref_str=<unavailable>, match=<unavailable>) at string.c:6619:16 [artificial]
    frame Shopify#12: 0x00000001002287f4 ruby`rb_str_sub_bang [inlined] rb_pat_search(pat=4748462304, str=4748451168, pos=0, set_backref_str=1) at string.c:6626:12
    frame Shopify#13: 0x00000001002287dc ruby`rb_str_sub_bang(argc=1, argv=0x00000001381280d0, str=4748451168) at string.c:6668:11
    frame Shopify#14: 0x000000010022826c ruby`rb_str_sub
```

You can reproduce this by running:
```
RUBY_TESTOPTS="--name=/test_str_capitalize/" make test-all TESTS=test/ruby/test_m17n.comb
```

However, you need to run it with multiple ractors at once.

Co-authored-by: jhawthorn <john@hawthorn.email>
tekknolagi pushed a commit that referenced this pull request Jun 30, 2025
`name` is used via `RSTRING_PTR` within rb_str_catf, which may allocate
and thus potentially trigger GC. Although `name` is still referenced
by a local variable, the compiler might optimize away the reference
before the GC sees it, especially under aggressive optimization or when
debugging tools like ASAN are used.

This patch adds an explicit `RB_GC_GUARD` to ensure `name` is kept alive
until after the last use.

While it's not certain this is the root cause of the following observed
use-after-poison ASAN error, I believe this fix is indeed needed and
hopefully a likely candidate for preventing the error.

```
==1960369==ERROR: AddressSanitizer: use-after-poison on address 0x7ec6a00f1d88 at pc 0x5fb5bcafcf2e bp 0x7ffcc1178cb0 sp 0x7ffcc1178470
READ of size 61 at 0x7ec6a00f1d88 thread T0
    #0 0x5fb5bcafcf2d in __asan_memcpy (/tmp/ruby/build/trunk_asan/ruby+0x204f2d) (BuildId: 6d92c84a27b87cfd253c38eeb552593f215ffb3d)
    #1 0x5fb5bcde1fa5 in memcpy /usr/include/x86_64-linux-gnu/bits/string_fortified.h:29:10
    #2 0x5fb5bcde1fa5 in ruby_nonempty_memcpy /tmp/ruby/src/trunk_asan/include/ruby/internal/memory.h:758:16
    #3 0x5fb5bcde1fa5 in ruby__sfvwrite /tmp/ruby/src/trunk_asan/sprintf.c:1083:9
    Shopify#4 0x5fb5bcde1521 in BSD__sprint /tmp/ruby/src/trunk_asan/vsnprintf.c:318:8
    Shopify#5 0x5fb5bcde0fbc in BSD_vfprintf /tmp/ruby/src/trunk_asan/vsnprintf.c:1215:3
    Shopify#6 0x5fb5bcdde4b1 in ruby_vsprintf0 /tmp/ruby/src/trunk_asan/sprintf.c:1164:5
    Shopify#7 0x5fb5bcddd648 in rb_str_vcatf /tmp/ruby/src/trunk_asan/sprintf.c:1234:5
    Shopify#8 0x5fb5bcddd648 in rb_str_catf /tmp/ruby/src/trunk_asan/sprintf.c:1245:11
    Shopify#9 0x5fb5bcf97c67 in location_format /tmp/ruby/src/trunk_asan/vm_backtrace.c:462:9
    Shopify#10 0x5fb5bcf97c67 in location_to_str /tmp/ruby/src/trunk_asan/vm_backtrace.c:493:12
    Shopify#11 0x5fb5bcf90a37 in location_to_str_dmyarg /tmp/ruby/src/trunk_asan/vm_backtrace.c:795:12
    Shopify#12 0x5fb5bcf90a37 in backtrace_collect /tmp/ruby/src/trunk_asan/vm_backtrace.c:786:28
    Shopify#13 0x5fb5bcf90a37 in backtrace_to_str_ary /tmp/ruby/src/trunk_asan/vm_backtrace.c:804:9
    Shopify#14 0x5fb5bcf90a37 in rb_backtrace_to_str_ary /tmp/ruby/src/trunk_asan/vm_backtrace.c:816:9
    Shopify#15 0x5fb5bd335b25 in exc_backtrace /tmp/ruby/src/trunk_asan/error.c:1904:15
    Shopify#16 0x5fb5bd335b25 in rb_get_backtrace /tmp/ruby/src/trunk_asan/error.c:1924:16
```
https://ci.rvm.jp/results/trunk_asan@ruby-sp1/5810304
tekknolagi pushed a commit that referenced this pull request Jul 11, 2025
This change addresses the following ASAN error:

```
==1973462==ERROR: AddressSanitizer: heap-use-after-free on address 0x5110002117dc at pc 0x749c307c8a65 bp 0x7ffc3af331d0 sp 0x7ffc3af331c8
READ of size 4 at 0x5110002117dc thread T0
    #0 0x749c307c8a64 in rb_getaddrinfo /tmp/ruby/src/trunk_asan/ext/socket/raddrinfo.c:564:14
    #1 0x749c307c8a64 in rsock_getaddrinfo /tmp/ruby/src/trunk_asan/ext/socket/raddrinfo.c:1008:21
    #2 0x749c307cac48 in rsock_addrinfo /tmp/ruby/src/trunk_asan/ext/socket/raddrinfo.c:1049:12
    #3 0x749c307b10ae in init_inetsock_internal /tmp/ruby/src/trunk_asan/ext/socket/ipsocket.c:62:23
    Shopify#4 0x562c5b2e327e in rb_ensure /tmp/ruby/src/trunk_asan/eval.c:1080:18
    Shopify#5 0x749c307aafd4 in rsock_init_inetsock /tmp/ruby/src/trunk_asan/ext/socket/ipsocket.c:1318:12
    Shopify#6 0x749c307b3b78 in tcp_svr_init /tmp/ruby/src/trunk_asan/ext/socket/tcpserver.c:39:12
```

Fixed to avoid accessing memory that has already been freed after calling `free_getaddrinfo_arg`.
tekknolagi added a commit that referenced this pull request Jul 11, 2025
This is notably faster: no need to hash indices.

Before:

```
plum% samply record ~/.rubies/ruby-zjit/bin/ruby --zjit benchmarks/getivar.rb
ruby 3.5.0dev (2025-07-10T14:40:49Z master 51252ef) +ZJIT dev +PRISM [arm64-darwin24]
itr:   time
 #1: 5311ms
 #2:   49ms
 #3:   49ms
 Shopify#4:   48ms
```

After:

```
plum% samply record ~/.rubies/ruby-zjit/bin/ruby --zjit benchmarks/getivar.rb
ruby 3.5.0dev (2025-07-10T15:09:06Z mb-benchmark-compile 42ffd3c) +ZJIT dev +PRISM [arm64-darwin24]
itr:   time
 #1: 1332ms
 #2:   49ms
 #3:   48ms
 Shopify#4:   48ms
```
tekknolagi pushed a commit that referenced this pull request Jul 28, 2025
Previously, ZJIT miscompiled the following because of native SP
interference.

    def a(n1,n2,n3,n4,n5,n6,n7,n8) = [n8]
    a(0,0,0,0,0,0,0, :ok)

Commented problematic disassembly:

    ; call rb_ary_new_capa
    mov x0, #1
    mov x16, #0x1278
    movk x16, #0x4bc, lsl Shopify#16
    movk x16, #1, lsl Shopify#32
    blr x16
    ; call rb_ary_push
    mov x1, x0
    str x1, [sp, #-0x10]! ; c_push() from alloc_regs()
    mov x0, x1            ; arg0, the array
    ldur x1, [sp]         ; meant to be arg1=n8, but sp just moved!
    mov x16, #0x3968
    movk x16, #0x4bc, lsl Shopify#16
    movk x16, #1, lsl Shopify#32
    blr x16

Since the frame pointer stays constant in the body of the function,
static offsets based on it don't run the risk of being invalidated by SP
movements.

Pass the registers to preserve through Insn::FrameSetup. This allows ARM
to use STP and waste no gaps between EC, SP, and CFP.

x86 now preserves and restores RBP since we use it as the frame pointer.
Since all arches now have a frame pointer, remove offset based SP
movement in the epilogue and restore registers using the frame pointer.
tekknolagi pushed a commit that referenced this pull request Aug 1, 2025
During Ruby's shutdown, we no longer need to check the fstr of the symbol
because we don't use the fstr anymore for freeing the symbol. This can also
fix the following ASAN error:

==2721247==ERROR: AddressSanitizer: use-after-poison on address 0x75fa90a627b8 at pc 0x64a7b06fb4bc bp 0x7ffdf95ba9b0 sp 0x7ffdf95ba9a8
READ of size 8 at 0x75fa90a627b8 thread T0
    #0 0x64a7b06fb4bb in RB_BUILTIN_TYPE include/ruby/internal/value_type.h:191:30
    #1 0x64a7b06fb4bb in rb_gc_shutdown_call_finalizer_p gc.c:357:18
    #2 0x64a7b06fb4bb in rb_gc_impl_shutdown_call_finalizer gc/default/default.c:3045:21
    #3 0x64a7b06fb4bb in rb_objspace_call_finalizer gc.c:1739:5
    Shopify#4 0x64a7b06ca1b2 in rb_ec_finalize eval.c:165:5
    Shopify#5 0x64a7b06ca1b2 in rb_ec_cleanup eval.c:256:5
    Shopify#6 0x64a7b06c98a3 in ruby_cleanup eval.c:179:12
tekknolagi pushed a commit that referenced this pull request Sep 29, 2025
rb_profile_frames() is used by profilers in a way such that it can run
on any instruction in the binary, and it crashed previously in the
following situation in `RUBY_DEBUG` builds:

```
* thread #1, queue = 'com.apple.main-thread', stop reason = step over
    frame #0: 0x00000001002827f0 miniruby`vm_make_env_each(ec=0x0000000101866b00, cfp=0x000000080c91bee8) at vm.c:992:74
   989              }
   990
   991              vm_make_env_each(ec, prev_cfp);
-> 992              VM_FORCE_WRITE_SPECIAL_CONST(&ep[VM_ENV_DATA_INDEX_SPECVAL], VM_GUARDED_PREV_EP(prev_cfp->ep));
   993          }
   994      }
   995      else {
(lldb) call rb_profile_frames(0, 100, $2, $3)
/Users/alan/ruby/vm_core.h:1448: Assertion Failed: VM_ENV_FLAGS:FIXNUM_P(flags)
ruby 3.5.0dev (2025-09-23T20:20:04Z master 06b7a70) +PRISM [arm64-darwin25]

-- Crash Report log information --------------------------------------------
   See Crash Report log file in one of the following locations:
     * ~/Library/Logs/DiagnosticReports
     * /Library/Logs/DiagnosticReports
   for more details.
Don't forget to include the above Crash Report log file in bug reports.

-- Control frame information -----------------------------------------------
c:0008 p:---- s:0029 e:000028 CFUNC  :lambda
/Users/alan/ruby/vm_core.h:1448: Assertion Failed: VM_ENV_FLAGS:FIXNUM_P(flags)
ruby 3.5.0dev (2025-09-23T20:20:04Z master 06b7a70) +PRISM [arm64-darwin25]

-- Crash Report log information --------------------------------------------
<snip>
```

There is a small window where the control frame is invalid and fails the
assert.

The double crash also shows that in `RUBY_DEBUG` builds, the crash reporter was
previously not resilient to corrupt frame state. In release builds, it
prints more info.

Add unchecked APIs for the crash reporter and profilers so they work
as well in `RUBY_DEBUG` builds as non-debug builds.
tekknolagi pushed a commit that referenced this pull request Oct 9, 2025
We need to free the current_block_exits in parse_program when we're done
with it to prevent memory leaks. This fixes the following memory leak detected
when running Ruby using `RUBY_FREE_AT_EXIT=1 ruby -nc -e "break"`:

    Direct leak of 32 byte(s) in 1 object(s) allocated from:
        #0 0x5bd3c5bc66c8 in realloc (miniruby+0x616c8) (BuildId: ruby/prism@ba6a96e5a060)
        #1 0x5bd3c5f91fd9 in pm_node_list_grow prism/templates/src/node.c.erb:35:40
        #2 0x5bd3c5f91e9d in pm_node_list_append prism/templates/src/node.c.erb:48:9
        #3 0x5bd3c6001fa0 in parse_block_exit prism/prism.c:15788:17
        Shopify#4 0x5bd3c5fee155 in parse_expression_prefix prism/prism.c:19221:50
        Shopify#5 0x5bd3c5fe9970 in parse_expression prism/prism.c:22235:23
        Shopify#6 0x5bd3c5fe0586 in parse_statements prism/prism.c:13976:27
        Shopify#7 0x5bd3c5fd6792 in parse_program prism/prism.c:22508:40

ruby/prism@fdf9b8d24a
tekknolagi pushed a commit that referenced this pull request Oct 23, 2025
When RUBYOPT is invalid, it raises an error which causes moreswitches
to leak memory. It can be seen when building with LSAN enabled:

    $ RUBY_FREE_AT_EXIT=1 RUBYOPT=f ruby
    ruby: invalid option -f  (-h will show valid options) (RuntimeError)

    Direct leak of 16 byte(s) in 1 object(s) allocated from:
        #0 0x618cef8efa23 in malloc (miniruby+0x64a23)
        #1 0x618cefa0e8d8 in rb_gc_impl_malloc gc/default/default.c:8182:5
        #2 0x618cef9f7f01 in ruby_xmalloc2_body gc.c:5182:12
        #3 0x618cef9f7eac in ruby_xmalloc2 gc.c:5176:34
        Shopify#4 0x618cefb547b2 in moreswitches ruby.c:919:18
        Shopify#5 0x618cefb526fe in process_options ruby.c:2350:9
        Shopify#6 0x618cefb524ac in ruby_process_options ruby.c:3202:12
        Shopify#7 0x618cef9dc11f in ruby_options eval.c:119:16
        Shopify#8 0x618cef8f2fb5 in rb_main main.c:42:26
        Shopify#9 0x618cef8f2f59 in main main.c:62:12
tekknolagi pushed a commit that referenced this pull request Nov 4, 2025
We can avoid taking this barrier if we're not incremental marking or lazy sweeping.
I found this was taking a significant amount of samples when profiling `Psych.load`
in multiple ractors due to the vm barrier. With this change, we get significant improvements
in ractor benchmarks that allocate lots of objects.

-- Psych.load benchmark --

```
Before:            After:
r:   itr:   time   r:   itr:   time
0    #1:  960ms    0    #1:  943ms
0    #2:  979ms    0    #2:  939ms
0    #3:  968ms    0    #3:  948ms
0    Shopify#4:  963ms    0    Shopify#4:  946ms
0    Shopify#5:  964ms    0    Shopify#5:  944ms
1    #1:  947ms    1    #1:  940ms
1    #2:  950ms    1    #2:  947ms
1    #3:  962ms    1    #3:  950ms
1    Shopify#4:  947ms    1    Shopify#4:  945ms
1    Shopify#5:  947ms    1    Shopify#5:  943ms
2    #1: 1131ms    2    #1: 1005ms
2    #2: 1153ms    2    #2:  996ms
2    #3: 1155ms    2    #3: 1003ms
2    Shopify#4: 1205ms    2    Shopify#4: 1012ms
2    Shopify#5: 1179ms    2    Shopify#5: 1012ms
4    #1: 1555ms    4    #1: 1209ms
4    #2: 1509ms    4    #2: 1244ms
4    #3: 1529ms    4    #3: 1254ms
4    Shopify#4: 1512ms    4    Shopify#4: 1267ms
4    Shopify#5: 1513ms    4    Shopify#5: 1245ms
6    #1: 2122ms    6    #1: 1584ms
6    #2: 2080ms    6    #2: 1532ms
6    #3: 2079ms    6    #3: 1476ms
6    Shopify#4: 2021ms    6    Shopify#4: 1463ms
6    Shopify#5: 1999ms    6    Shopify#5: 1461ms
8    #1: 2741ms    8    #1: 1630ms
8    #2: 2711ms    8    #2: 1632ms
8    #3: 2688ms    8    #3: 1654ms
8    Shopify#4: 2641ms    8    Shopify#4: 1684ms
8    Shopify#5: 2656ms    8    Shopify#5: 1752ms
```
tekknolagi pushed a commit that referenced this pull request Nov 10, 2025
We were seeing errors like:

```
* thread Shopify#8, stop reason = EXC_BAD_ACCESS (code=1, address=0x803)
  * frame #0: 0x00000001001fe944 ruby`rb_st_lookup(tab=0x00000000000007fb, key=1, value=0x00000001305b7490) at st.c:1066:22
    frame #1: 0x000000010002d658 ruby`remove_class_from_subclasses [inlined] class_get_subclasses_for_ns(tbl=0x00000000000007fb, ns_id=1) at class.c:604:9
    frame #2: 0x000000010002d650 ruby`remove_class_from_subclasses(tbl=0x00000000000007fb, ns_id=1, klass=4754039232) at class.c:620:34
    frame #3: 0x000000010002c8a8 ruby`rb_class_classext_free_subclasses(ext=0x000000011b5ce1d8, klass=4754039232, replacing=<unavailable>) at class.c:700:9
    frame Shopify#4: 0x000000010002c760 ruby`rb_class_classext_free(klass=4754039232, ext=0x000000011b5ce1d8, is_prime=true) at class.c:105:5
    frame Shopify#5: 0x00000001000e770c ruby`classext_free(ext=<unavailable>, is_prime=<unavailable>, namespace=<unavailable>, arg=<unavailable>) at gc.c:1231:5 [artificial]
    frame Shopify#6: 0x000000010002d178 ruby`rb_class_classext_foreach(klass=<unavailable>, func=(ruby`classext_free at gc.c:1228), arg=0x00000001305b75c0) at class.c:518:5
    frame Shopify#7: 0x00000001000e745c ruby`rb_gc_obj_free(objspace=0x000000012500c400, obj=4754039232) at gc.c:1282:9
    frame Shopify#8: 0x00000001000e70d4 ruby`gc_sweep_plane(objspace=0x000000012500c400, heap=<unavailable>, p=4754039232, bitset=4095, ctx=0x00000001305b76e8) at default.c:3482:21
    frame Shopify#9: 0x00000001000e6e9c ruby`gc_sweep_page(objspace=0x000000012500c400, heap=0x000000012500c540, ctx=0x00000001305b76e8) at default.c:3567:13
    frame Shopify#10: 0x00000001000e51d0 ruby`gc_sweep_step(objspace=0x000000012500c400, heap=0x000000012500c540) at default.c:3848:9
    frame Shopify#11: 0x00000001000e1880 ruby`gc_continue [inlined] gc_sweep_continue(objspace=0x000000012500c400, sweep_heap=0x000000012500c540) at default.c:3931:13
    frame Shopify#12: 0x00000001000e1754 ruby`gc_continue(objspace=0x000000012500c400, heap=0x000000012500c540) at default.c:2037:9
    frame Shopify#13: 0x00000001000e10bc ruby`newobj_cache_miss [inlined] heap_prepare(objspace=0x000000012500c400, heap=0x000000012500c540) at default.c:2056:5
    frame Shopify#14: 0x00000001000e1074 ruby`newobj_cache_miss [inlined] heap_next_free_page(objspace=0x000000012500c400, heap=0x000000012500c540) at default.c:2280:9
    frame Shopify#15: 0x00000001000e106c ruby`newobj_cache_miss(objspace=0x000000012500c400, cache=0x0000600001b00300, heap_idx=2, vm_locked=false) at default.c:2387:38
    frame Shopify#16: 0x00000001000e0d28 ruby`newobj_alloc(objspace=<unavailable>, cache=<unavailable>, heap_idx=<unavailable>, vm_locked=<unavailable>) at default.c:2411:15 [artificial]
    frame Shopify#17: 0x00000001000d7214 ruby`newobj_of [inlined] rb_gc_impl_new_obj(objspace_ptr=<unavailable>, cache_ptr=<unavailable>, klass=<unavailable>, flags=<unavailable>, wb_protected=<unavailable>, alloc_size=<unavailable>) at default.c:2490:15
    frame Shopify#18: 0x00000001000d719c ruby`newobj_of(cr=<unavailable>, klass=4313971728, flags=258, wb_protected=<unavailable>, size=<unavailable>) at gc.c:995:17
    frame Shopify#19: 0x00000001000d73ec ruby`rb_wb_protected_newobj_of(ec=<unavailable>, klass=<unavailable>, flags=<unavailable>, size=<unavailable>) at gc.c:1044:12 [artificial]
    frame Shopify#20: 0x0000000100032d34 ruby`class_alloc0(type=<unavailable>, klass=4313971728, namespaceable=<unavailable>) at class.c:803:5
```
XrXr pushed a commit that referenced this pull request Nov 13, 2025
We don't decrement the super and module subclasses count for iclasses that
are having their classext replaced. This causes the reference count to be
incorrect and leak memory.

The following script demonstrates the memory leak:

    module Foo
      refine(Object) do
        define_method(:<=) {}
      end
    end

    class Bar
      include Comparable
    end

With RUBY_FREE_AT_EXIT and ASAN, we can see many memory leaks, including:

    Direct leak of 16 byte(s) in 1 object(s) allocated from:
        #0 0x599f715adca2 in calloc (miniruby+0x64ca2)
        #1 0x599f716bd779 in calloc1 gc/default/default.c:1495:12
        #2 0x599f716d1370 in rb_gc_impl_calloc gc/default/default.c:8216:5
        #3 0x599f716b8ab1 in ruby_xcalloc_body gc.c:5221:12
        Shopify#4 0x599f716b269c in ruby_xcalloc gc.c:5215:34
        Shopify#5 0x599f715eab23 in class_alloc0 class.c:790:22
        Shopify#6 0x599f715e4bec in class_alloc class.c:836:12
        Shopify#7 0x599f715e60c9 in module_new class.c:1693:17
        Shopify#8 0x599f715e60a2 in rb_module_new class.c:1701:12
        Shopify#9 0x599f715e6303 in rb_define_module class.c:1733:14
        Shopify#10 0x599f715ebc5f in Init_Comparable compar.c:315:22
        Shopify#11 0x599f716e35f5 in rb_call_inits inits.c:32:5
        Shopify#12 0x599f7169cbfd in ruby_setup eval.c:88:9
        Shopify#13 0x599f7169cdac in ruby_init eval.c:100:17
        Shopify#14 0x599f715b0fa9 in rb_main main.c:41:5
        Shopify#15 0x599f715b0f59 in main main.c:62:12
        Shopify#16 0x739b2f02a1c9 in __libc_start_call_main csu/../sysdeps/nptl/libc_start_call_main.h:58:16
        Shopify#17 0x739b2f02a28a in __libc_start_main csu/../csu/libc-start.c:360:3
        Shopify#18 0x599f7157c424 in _start (miniruby+0x33424)
tekknolagi pushed a commit that referenced this pull request Nov 15, 2025
These tests use NM threads but NT is not freed for MN thread, causing it
to be reported as memory leaks in LSAN. For example:

    #1 0x62ee7bc67e99 in calloc1 gc/default/default.c:1495:12
    #2 0x62ee7bc7ba00 in rb_gc_impl_calloc gc/default/default.c:8216:5
    #3 0x62ee7bc631d1 in ruby_xcalloc_body gc.c:5221:12
    Shopify#4 0x62ee7bc5cdbc in ruby_xcalloc gc.c:5215:34
    Shopify#5 0x62ee7bdea4c6 in native_thread_alloc thread_pthread.c:2187:35
    Shopify#6 0x62ee7bdec31b in native_thread_check_and_create_shared thread_pthread_mn.c:429:39
    Shopify#7 0x62ee7bdea484 in native_thread_create_shared thread_pthread_mn.c:531:12
    Shopify#8 0x62ee7bdea1da in native_thread_create thread_pthread.c:2403:16
    Shopify#9 0x62ee7bdde2eb in thread_create_core thread.c:884:11
    Shopify#10 0x62ee7bde4466 in thread_initialize thread.c:992:16
tekknolagi pushed a commit that referenced this pull request Dec 22, 2025
This reverts commit 2f151e7.

The SP decrement (push) before the call do not match up with
the pops after the call, so registers were restored incorrectly.

Code from:

    ./miniruby --zjit-call-threshold=1 --zjit-dump-disasm -e 'p Time.new(1992, 9, 23, 23, 0, 0, :std)'

    str x11, [sp, #-0x10]!
    str x12, [sp, #-0x10]!
    stur x7, [sp]              # last argument
    mov x0, x20
    mov x7, x6
    mov x6, x5
    mov x5, x4
    mov x4, x3
    mov x3, x2
    mov x2, x1
    ldur x1, [x29, #-0x20]
    mov x16, #0xccfc
    movk x16, #0x2e7, lsl Shopify#16
    movk x16, #1, lsl Shopify#32
    blr x16
    ldr x12, [sp], #0x10       # supposed to match str x12, [sp, #-0x10]!, but got last argument
    ldr x11, [sp], #0x10
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants