103700 Commits

Author SHA1 Message Date
Kazuki Yamaguchi
e67e4a6960 [ruby/openssl] ssl: remove dependency on io/nonblock
Use C API rb_io_set_nonblock() instead.

https://github.com/ruby/openssl/commit/7bf23b629e
2026-11-07 16:07:23 +00:00
Kazuki Yamaguchi
9fc86fc5f9 [ruby/openssl] cipher: fix use-after-free in in-place Cipher#update
Take RSTRING_PTR() of the input buffer after resizing the output
buffer, as the input and output buffers may be the same String object.

Also explicitly reject in-place Cipher#update when the input is too
large to process in a single EVP_CipherUpdate() call. We should not
implicitly split the input across multiple calls for in-place
operation because this appears to be unreliable.

Reported by TheSecguy <thesecguy45@gmail.com>.

https://github.com/ruby/openssl/commit/8df76d73ba
2026-11-07 15:18:19 +00:00
Nobuyoshi Nakada
11589a5b92 Check Bignum arguments in C API specs
Reject non-Bignum values before Bignum-only APIs can access their representation.
2026-11-08 00:17:57 +09:00
Nobuyoshi Nakada
2019f0f50e Test Bignum conversions against rb_len_t bounds
Conversion outcomes depend on how the rb_len_t range compares with C integer ranges.
2026-11-08 00:17:57 +09:00
Yusuke Endoh
d8d20bf097 Reserve the maximum character length in tr_buffer_mbcput
A character that is not replaced by String#tr with a Hash can be longer
than 4 bytes, e.g., 6 bytes for a supplementary character in CESU-8.

Reported-by: Regy Robson (https://github.com/Atract0n)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-07 10:34:37 +01:00
Yusuke Endoh
aec71b2a5b [ruby/zlib] Update the buffer length before expanding it in Deflate#params
When deflateParams returned Z_BUF_ERROR, the buffer was expanded before
the bytes just written were added to its length, so the next call wrote
over them and the length was counted twice.

Reported-by: Dániel Percze (https://hackerone.com/flashmyname)

https://github.com/ruby/zlib/commit/cba9abc7bd

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-07 03:41:29 +00:00
Hiroshi SHIBATA
e21a3dcf36 [ruby/zlib] Pass the input beyond UINT_MAX bytes to zlib
avail_in is a uInt, and the input past the first UINT_MAX bytes was discarded. Zlib::Deflate.deflate and Zlib::GzipWriter#write silently lost the tail of a longer input, and Zlib::Inflate.inflate raised Zlib::BufError on longer compressed input.

  src = "a" * (2**32 + 1)
  Zlib::Inflate.inflate(Zlib::Deflate.deflate(src)).bytesize
  # expected: https://github.com/ruby/zlib/commit/4294967297
  # actual:   https://github.com/ruby/zlib/commit/4294967295

https://github.com/ruby/zlib/commit/cbbf448388

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-07 03:40:38 +00:00
Hiroshi SHIBATA
4684fdbccd Reject an insertion whose result does not fit in rb_len_t
slen + vlen - len in rb_str_update_1 could wrap around where rb_len_t is 32 bits wide. Check it before the capacity test, as str_buf_cat4 does.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-07 10:28:51 +09:00
Hiroshi SHIBATA
90db216256 Cast the capacity to rb_len_t to fix the sign-compare warning
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-07 10:28:51 +09:00
Hiroshi SHIBATA
16d12f213e Keep the capacity in rb_str_update_1 when the insertion fits
RESIZE_CAPA reallocates a heap string to the exact size, so an insertion by bytesplice or String#[]= shrank a buffer that already had room, and the next append grew it again. Each of those reallocs can move and copy the whole buffer.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-07 10:28:51 +09:00
Max Bernstein
60b8afc426
ZJIT: Don't clone FrameState in queue for HIR building (#19760)
We only use it for local table size and stack size, not for its actual
contents.
2026-11-06 18:31:12 -05:00
Matt Valentine-House
c78695fc36 [ruby/mmtk] Keep Ruby's GC disable state across a forced GC.start
GC.start has to run even when GC is disabled, so we enable collection,
run the GC and then disable it again. #134 fixed the crash we saw when
another Ractor requested a GC before we could re-disable, but we still
restore whatever state we saw before the GC.

That's a problem when another Ractor changes the state in the meantime.
If it enables GC while we're collecting, we disable it again on its
behalf and GC stays off for good. Ractor.new disables and enables GC
around thread allocation, so this isn't hard to hit. GC.disable and the
internal gc_disable also share a single flag in mmtk-core, so one can
undo the other.

In this commit we track the internal flag, the user flag and any forced
GC.start requests in the binding, and mirror the combined state into
mmtk-core. A forced GC.start only enables collection until the next
pause ends, and we reapply the state in resume_mutators before any
mutator can request another GC.

GC workers also toggle the internal flag during a pause, through
DURING_GC_COULD_MALLOC_REGION. That reads the flag and then sets it, so
two workers running in parallel can leave it set. mmtk-core used to
ignore these because it can't disable collection mid-pause, so we do the
same and drop internal changes between stop_all_mutators and
resume_mutators.

This replaces the retry loop from #134, if we fail to disable because a
GC is pending, the end of that GC puts the state right.

AtomicU64::update needs Rust 1.95, so we declare that in Cargo.toml.

https://github.com/ruby/mmtk/commit/7430ebeaa6
2026-11-06 22:13:40 +00:00
Matt Valentine-House
bf1ad76f11 [ruby/mmtk] Compact obj_free candidates in place
use retain_mut in process_obj_free_candidates instead of building a new
Vec on every GC.

This saves about 38MiB of peak RSS when running the Lobsters benchmark
with 12 workers.

https://github.com/ruby/mmtk/commit/1292d9a488
2026-11-06 22:13:12 +00:00
Matt Valentine-House
24de362169 [ruby/mmtk] Distribute free candidates without a modulo per object
add_obj_free_candidates_batch walked the whole batch once for every
bucket and kept the objects where i % num_buckets == idx. Each flush of
128 candidates ran 128 * num_buckets modulo operations on the mutator
thread. There is one bucket per GC worker, so the cost grew with the
number of cores.

In this commit we visit only the objects that belong to each bucket
with skip(idx).step_by(num_buckets). Each object still goes to bucket
i % num_buckets, and each flush visits every object once.

On a c6i.metal with 64 GC workers, the ruby-bench headline geomean
speedup with YJIT is 1.15x. With 1 GC worker there is no change.

https://github.com/ruby/mmtk/commit/477de42ae7
2026-11-06 22:12:34 +00:00
XrXr
3e79ec18dc ZJIT: A64: Remove unnecessary reg=reg+0 from IncrCounter 2026-11-06 16:30:52 -05:00
Luke Gruber
1974cdddb9 Make blockparamproxy shareable
Fixes YJIT compilation bug. During YJIT compilation, it could see a
`Ractor::IsolationError` by getting the attached object of the blockparamproxy's
singleton class's (the proxy object). This object needs to be shareable in order
for the compilation to work on a non-main Ractor.
2026-11-06 15:31:56 -05:00
Matt Valentine-House
6702f60a25 Read fields_obj atomically too 2026-11-06 20:26:40 +00:00
Matt Valentine-House
2a8f329f59 Read the object_id of a shareable T_DATA without the VM lock
object_id took the VM lock for every shareable object in multi-Ractor mode, even
when the object already had an id.

Kernel#hash reaches object_id through rb_obj_hash, so a shareable T_DATA such as
an Encoding, a Ractor or a Ractor::Port used as a Hash key serialised every
lookup across Ractors.

In this commit we make generic_field_set copy the fields of a shareable object
in multi-Ractor mode, and publish the new fields_obj of a T_DATA with an atomic
write.

```ruby
t = Process.clock_gettime(Process::CLOCK_MONOTONIC)
ractors = 4.times.map do
  Ractor.new do
    h = { Encoding::UTF_8 => 1 }
    1_000_000.times { h[Encoding::UTF_8] }
  end
end
ractors.each(&:join)
elapsed = Process.clock_gettime(Process::CLOCK_MONOTONIC) - t
puts "#{elapsed.round(2)}s"
```

I ran this 3 times before this patch and after and saw

    before: 0.58s 0.61s 0.64s
    after:  0.05s 0.05s 0.05s
2026-11-06 20:26:40 +00:00
Max Bernstein
1f44a8642a
ZJIT: Specialize polymorphic class + monomorphic shape (#19443)
If we have dispatch where the receiver is polymorphic in a class, right
now we just break up the dispatch by the class. This unfortunately leads
to polymorphic `attr_reader` being completely unspecialized by shape.

In this commit, make sure we, for each polymorphic branch, filter the
profiled types by the receiver's specialized class. That way we still
get a chance at monomorphizing by shape and specializing `attr_reader`
away.
2026-11-06 19:47:31 +00:00
pgorgita
d38a6f683d [ruby/openssl] Fix ASN.1 OID conversion at buffer boundary
Retry OBJ_obj2txt when the required length equals the buffer capacity.

https://github.com/ruby/openssl/commit/6b9cb7bf07
2026-11-06 19:40:56 +00:00
Nobuyoshi Nakada
338c55e07e
Check reentry after comparison conversion
Comparison result conversion can invoke Ruby code before reentry is
checked.
2026-11-07 02:48:00 +09:00
Nobuyoshi Nakada
c5943e4975
Use OPTIMIZED_CMP in Array#sort
Array sorting should share the common optimized comparison paths.
2026-11-07 02:48:00 +09:00
Kevin Newton
6cd25700b5 [ruby/prism] Extend state stacks indefinitely
An old and very obscure bug resulting from using fixed-size
integers to hold state stacks.

Prism uses u32, and parse.y uses u64. Both of them have problems
if they overflow. Instead, use a growable state stack that can
extend indefinitely so this is never a problem.

https://github.com/ruby/prism/commit/372df2460f
2026-11-06 16:58:49 +00:00
Luke Gruber
13786f1302 Fix failing ractor test under MMTk 2026-11-06 11:18:26 -05:00
Kevin Newton
3026e09ec5 [ruby/prism] Add our own PRISM_ASSERT
https://github.com/ruby/prism/commit/2d4a6b7d06
2026-11-06 13:34:38 +00:00
Kevin Newton
d1104ade2e [ruby/prism] Use memcmp instead of strncmp
https://github.com/ruby/prism/commit/0ef4e8a941
2026-11-06 13:34:37 +00:00
Kevin Newton
702f03d471 [ruby/prism] Use PRISM_OOM for all allocations
https://github.com/ruby/prism/commit/387324d7e9
2026-11-06 13:34:37 +00:00
Hiroshi SHIBATA
0236df43c2 Keep the #to_set wording in the Set overview
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-06 17:56:06 +09:00
Hiroshi SHIBATA
59daf92c11 Mention Enumerable#to_set in the Set and Enumerable overviews
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-06 17:56:06 +09:00
Hiroshi SHIBATA
cdc036650c Move Enumerable#to_set from prelude.rb to set.c
Set is a core class implemented in C now, so define Enumerable#to_set there and let Set#to_set share it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-06 17:56:06 +09:00
Hiroshi SHIBATA
723592e27a mswin: Link compiler-rt builtins with clang-cl
Extensions calling __builtin_cpu_supports, such as json 3.1.0 and older, failed to link against a clang-cl build with an undefined __cpu_model, which compiler-rt defines and clang-cl does not link by default.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-06 17:05:51 +09:00
Hiroshi SHIBATA
791317f5ae Test that require in a box reports a frozen $LOADED_FEATURES
A box always rebuilds its feature index on the first require, so this
covers the rebuild path that test_require.rb reaches only after
$LOADED_FEATURES has been modified.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-11-06 17:04:35 +09:00
Hiroshi SHIBATA
c9cfbc3f04 Do not write back a frozen $LOADED_FEATURES while rebuilding its index
A frozen array is never shared, so the check for user modifications
always fires and rb_ary_replace() raises FrozenError before
rb_provide_feature() can report the freeze.  Appending to
$LOADED_FEATURES before freezing it is enough to reach this.  Under
RUBY_BOX=1 every box reaches it, because a box starts with an empty
index snapshot.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-11-06 17:04:35 +09:00
Hiroshi SHIBATA
033fdefd80 [ruby/stringio] Remove no-op self-assignment of rs
This came from io.c, where the converted separator is written back through a pointer argument. Inlined here it became a self-assignment:

    stringio.c:1507:6: warning: explicitly assigning value of variable of type 'VALUE' (aka 'unsigned long') to itself [-Wself-assign]
     1507 |                 rs = rs;
          |                 ~~ ^ ~~

https://github.com/ruby/stringio/commit/f434104c18

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-11-06 07:59:10 +00:00
Nobuyoshi Nakada
37003e92e8 [ruby/test-unit-ruby-core] Freeze RbConfig.ruby for sharing among Ractors
https://github.com/ruby/test-unit-ruby-core/commit/677bcb7206
2026-11-06 04:47:16 +00:00
Hiroshi SHIBATA
30fd927272 Build the fast fallback of TCPSocket.new on mswin
Every piece the Happy Eyeballs Version 2 path needed from pthread, pipe(2) and select(2) now has a Windows counterpart, so a host that answers with both families no longer waits for the IPv6 attempt to time out there. MinGW stays out, since its pthread emulation was never tested against this path, and its tests are omitted instead of passing by connecting sequentially.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-11-06 10:44:26 +09:00
Hiroshi SHIBATA
d81710bca7 Read the resolution error and SO_ERROR the way Winsock declares them
Winsock has no EAI_ADDRFAMILY, and its getsockopt(2) takes a char * where the option value is an int. Neither compiles as written once the fast fallback is built for Windows.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-11-06 10:44:26 +09:00
Hiroshi SHIBATA
1813275e7e Wait for the exceptfds of the connecting sockets on Windows
Winsock reports a failed non-blocking connect(2) through the exceptfds of select(2) alone, so the fast fallback never learned that an attempt had been refused. Only Windows fills the set, so select(2) behaves as before elsewhere.

[Bug #18661]

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-11-06 10:44:26 +09:00
Hiroshi SHIBATA
f902d4822d Notify the hostname resolution through a pipe on Windows as well
rb_w32_select_with_thread() polls the read end of a pipe, so the resolution threads can report through one there too. The waiter goes through nonblock_set() because the Windows fcntl() has no F_GETFL.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-11-06 10:44:26 +09:00
Hiroshi SHIBATA
6c342f179b Restore blocking mode on the fast fallback socket on Windows
The connection attempts race each other non-blocking, and TCPSocket.new wrapped the winner as it was. Windows creates every other socket blocking, and a read parked on a non-blocking one there cannot be interrupted by IO#close. POSIX sockets start out non-blocking, so leave them alone and test that they stay so.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-11-06 10:44:26 +09:00
Hiroshi SHIBATA
4e38061ca4 Size the fast fallback arrays at compile time
cl.exe does not implement variable length arrays, and none of these ever holds more than the two address families the fast fallback resolves. The hints array only needed one live element at a time, so fill the entry in place instead.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-11-06 10:44:26 +09:00
Hiroshi SHIBATA
3df017d756 Build the fast fallback resolver thread body on Windows
Windows has neither SIGPIPE nor pthread_sigmask(3), so skip the masking there. The test-only resolution delay uses SleepEx() there, because Sleep() reaches rb_w32_Sleep() through the ruby DLL and waits through a Ruby thread this thread does not have.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-06 10:44:26 +09:00
Burdette Lamar
5d81cb4595
[DOC] Doc for MatchData#offset (#19716) 2026-11-06 01:35:58 +00:00
Burdette Lamar
0129627d9a
[DOC] Doc for MatchData#match (#19710) 2026-11-06 10:35:21 +09:00
Burdette Lamar
55c16817d0
[DOC] Doc for MatchData#post_match (#19717) 2026-11-06 10:30:58 +09:00
Burdette Lamar
b424f51a9d
[DOC] Doc for MatchData#pre_match (#19719) 2026-11-06 10:30:19 +09:00
Burdette Lamar
b4a0e978b0
[DOC] What's Here for MatchData 2026-11-06 10:27:05 +09:00
Thomas Klemm
f0de939f61
YJIT: Check singleton attached-object identity in C (GH-19648)
Use rb_yjit_attached_object_is() for the compile-time attachment check.
It keeps the singleton flag test in C and returns only a boolean to Rust.
The predicate cannot raise, allocate, or take locks. Guard emission is
unchanged, and the IO exclusion stays in Rust.
2026-11-06 00:24:11 +00:00
Matt Valentine-House
0dcc5b6ab5 [ruby/mmtk] Exclude flaky Gem::SafeYAML linear time test
test_load_block_scalar_strip_indicator_in_linear_time asserts on wall
clock time, and it fails intermittently when Ruby runs with MMTk.

https://github.com/ruby/mmtk/commit/627a8eca44
2026-11-05 23:08:31 +00:00
Hiroshi SHIBATA
f6996b73a2 CI: Build and test YJIT on arm64 mswin
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-06 07:15:38 +09:00