10919 Commits
Author SHA1 Message Date
Hiroshi SHIBATAandClaude Opus 5.5 021446fa21 Fix the timeout of getaddrinfo with a nil host or service
Building the error message from a NULL pointer raised ArgumentError instead of IO::TimeoutError.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-28 08:42:54 +09:00
Hiroshi SHIBATAandClaude Opus 5.5 47d566434f mswin: Resolve hostnames in a dedicated thread
Without pthread, mswin fell back to GETADDRINFO_IMPL 1, which ignores the timeout of Addrinfo.getaddrinfo and lets neither Timeout, Thread#kill nor Thread#raise stop the caller until getaddrinfo(3) returns. Start the resolver thread with _beginthreadex(3) so mswin takes GETADDRINFO_IMPL 2 as the pthread platforms do. MinGW stays on GETADDRINFO_IMPL 1.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-28 08:42:54 +09:00
Hiroshi SHIBATAandClaude Opus 5.5 a98386e422 Drop the unused thread handle from the resolver thread creation
No caller reads the pthread_t, so raddrinfo_thread_create() no longer takes one, and a non-pthread implementation can sit behind it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-28 08:42:54 +09:00
Hiroshi SHIBATAandClaude Opus 5.5 5d1d072289 [ruby/zlib] Fix the rdoc of Zlib::Inflate#sync
It described the return values the other way around, and did not mention Zlib::InProgressError.

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

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-26 07:29:52 +00:00
Hiroshi SHIBATAandClaude Opus 5.5 20a9f1a53d [ruby/zlib] Raise InProgressError from Zlib::Inflate#sync during inflate
Called from the block of Zlib::Inflate#inflate, #sync pointed next_in at its argument, and the inflate loop kept reading from there after the block returned.

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

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-26 07:29:52 +00:00
Hiroshi SHIBATAandClaude Opus 5.5 dd7782fafb [ruby/zlib] Fix Zlib::Inflate#sync with input over UINT_MAX bytes
inflateSync was given only the first UINT_MAX bytes, but the input was consumed as if all of it had been searched, so the data after the sync point was lost and a sync point past those bytes was never found.

  d = Zlib::Deflate.new(Zlib::DEFAULT_COMPRESSION, -Zlib::MAX_WBITS)
  src = "\0" * (2**32 - 5) + "\0\0\xFF\xFF".b + d.deflate("hello", Zlib::FINISH)
  z = Zlib::Inflate.new
  z.sync(src)   #=> true
  z.inflate("") #=> "" (expected "hello")

https://github.com/ruby/zlib/commit/6fb1cc91f8

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-26 04:33:18 +00:00
Hiroshi SHIBATAandClaude Opus 5.5 349d9d65bc Initialize the fast fallback waiter fd before anything can raise
An invalid open_timeout raised before the waiter was assigned, so the cleanup closed fd 0 left by memset and took the process's stdin with it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-25 14:16:14 +09:00
Hiroshi SHIBATAandClaude Opus 5.5 8380003270 [ruby/zlib] Fix Zlib.gunzip with a header truncated in the file name or comment
Reading the rest of the field went to the IO, which Zlib.gunzip does not have, instead of raising Zlib::GzipFile::Error as the other truncated header fields do.

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

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-25 03:39:46 +00:00
Hiroshi SHIBATAandClaude Opus 5.5 764d1d3a73 win32: Fix a handle leak in rb_w32_read_internal
One of its early returns after `setup_overlapped` did not close the event.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-25 11:57:31 +09:00
Yusuke EndohandClaude Opus 5.5 d85ad13d96 [ruby/zlib] Document the restrictions on the :buffer keyword of Zlib::Inflate#inflate
https://github.com/ruby/zlib/commit/09b43c5b84

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-24 19:57:18 +00:00
Yusuke EndohandClaude Mythos 5.1 b5cc0e49e8 [ruby/zlib] Carry over pending output when the inflate buffer is replaced
In the block form, output not yet yielded stays in the buffer between
calls. It was silently dropped when another buffer (or none) was given
for the next call.

  data = Zlib::Deflate.deflate("A" * 50000)
  half = data.bytesize / 2
  inf = Zlib::Inflate.new
  out = +""
  inf.inflate(data[0, half], buffer: String.new) { |c| out << c }
  inf.inflate(data[half..], buffer: String.new) { |c| out << c }
  out << inf.finish
  out.bytesize
  # expected: 50000
  # actual:   47806

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

Co-Authored-By: Claude Mythos 5.1 <noreply@anthropic.com>
2026-10-24 17:26:12 +00:00
Yusuke EndohandClaude Mythos 5.1 fa4615c89f [ruby/zlib] Clear ZSTREAM_REUSE_BUFFER when the output buffer is detached
The flag stayed set after a call with buffer: had returned its buffer,
so an internal buffer allocated by a later Inflate#<< was treated as
user-provided and never revealed.

  data = Zlib::Deflate.deflate("A" * 50000)
  half = data.bytesize / 2
  inf = Zlib::Inflate.new
  inf.inflate(data[0, half], buffer: String.new)
  inf << data[half..]
  inf.finish.class
  #=> [BUG] Segmentation fault

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

Co-Authored-By: Claude Mythos 5.1 <noreply@anthropic.com>
2026-10-24 17:26:12 +00:00
Yusuke EndohandClaude Mythos 5.1 7d104f9de0 [ruby/zlib] Fix stale next_out in Zlib::Inflate#inflate(buffer:)
When a call with buffer: left the stream in progress (it raised
Zlib::NeedDict, or the block form has more input to come), the next run
reused the next_out saved by the previous call. If the buffer had been
modified in between, it pointed into freed or reallocated memory.

  d = Zlib::Deflate.new
  d.set_dictionary("dict")
  data = d.deflate("A" * 12000, Zlib::FINISH)
  inf = Zlib::Inflate.new
  buf = String.new(capacity: 1 << 14)
  begin; inf.inflate(data, buffer: buf); rescue Zlib::NeedDict; end
  buf.clear
  inf.set_dictionary("dict")
  inf.inflate("", buffer: buf)
  #=> [BUG] probable buffer overflow: 12000 for 15

Re-derive next_out/avail_out from the buffer at the start of every run,
and reset them when buffer: is dropped.

Reported by richardjiakangsun (https://hackerone.com/richardjiakangsun).

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

Co-Authored-By: Claude Mythos 5.1 <noreply@anthropic.com>
2026-10-24 17:26:12 +00:00
Kazuki Yamaguchi f272b3e281 [ruby/openssl] ssl: fix NoMethodError on SAN dNSName with an empty label
Handle the empty label as a literal string.

OpenSSL::SSL::SSLSocket#post_connection_check can raise NoMethodError
when the server certificate contains a malformed subjectAltName
extension with a dNSName that starts with ".", such as ".example.com".

Reported by 4l1ve on HackerOne.

https://github.com/ruby/openssl/commit/1fb29e7ef5
2026-10-24 09:23:48 +00:00
Hiroshi SHIBATAandClaude Opus 5.5 6a81db9d5f Keep capture group indices in long
They index the match registers, whose count is an int, rather than a String, so rb_len_t does not apply. Only the length of a group name given as a String stays in rb_len_t.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-21 13:37:54 +09:00
Sebastian Turner 63ae538ecf [ruby/json] Fix ParserError#json_path with symbolize_names: true
Signed-off-by: Sebastian Turner <sebastiant3484@gmail.com>

https://github.com/ruby/json/commit/c839870678
2026-10-19 16:25:24 +00:00
Hiroshi SHIBATAandClaude Opus 5.5 09053cae8a Clamp the length given to Winsock send() to int
Winsock takes the length as int, so a String of 2GiB or more had its length truncated. The caller now sees a short write, as BasicSocket#send already reports one.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-19 16:07:39 +09:00
ShaisolarisandKazuki Yamaguchi f2bc42f6bf [ruby/openssl] ssl: raise ArgumentError for a negative length in SSLSocket
Check the length so that #sysread, #read_nonblock and the buffer
variants raise ArgumentError.

https://github.com/ruby/openssl/commit/9443e67e99

Co-authored-by: Kazuki Yamaguchi <k@rhe.jp>
2026-10-16 17:31:04 +00:00
Luke Gruber 4c2968348e Use mark context when marking execution_context 2026-10-16 12:33:52 -04:00
William T. NelsonandClaude Opus 5.5 f33766720c Socket.tcp_with_fast_fallback: Fix typo in getaddrinfo family
ADDRESS_FAMILIES[:family_name] used the Symbol :family_name as the key
instead of the local variable family_name, so the address family was
always nil. This is a follow-up to b896f80598 [Bug #21512].

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-15 23:19:44 +02:00
Douglas Eichelberger e06b9da3f2 Reset the fork lock in the child without unlocking it
A thread that is waiting for the fork lock when another thread forks
exists only in the parent, but on macOS the child's copy of the lock
still counts it. After the child unlocks its copy,
pthread_rwlock_destroy() and pthread_rwlock_init() fail with EBUSY, so
the child aborts with
"[BUG] pthread_rwlock_destroy: Resource busy (EBUSY)". Lookup threads
wait for the lock whenever a fork holds it, so a process that resolves
names in background threads while it forks loses a child now and then.

Reset the child's copy by assigning PTHREAD_RWLOCK_INITIALIZER, as
rb_internal_thread_event_hooks_rw_lock_atfork() does for its lock, and
do not unlock it first. With a waiter counted, macOS's unlock enters the
kernel to wake it, and the state that leaves behind for the lock's
address survives the assignment, so a later waiter in the child can
sleep forever although no thread holds the lock. FreeBSD already skipped
the unlock in the child (dc8c382266), and on glibc the child's unlock
does not release the write lock anyway.

[Bug #22445]
2026-10-15 20:23:08 +02:00
Hiroshi SHIBATAandClaude Opus 5.5 76f0a79179 [ruby/json] Drop the leftovers of runtime SSE2 detection
Neither the `__builtin_cpu_supports` probe in conf.rb nor `cpuid.h` has a use now that SSE2 is assumed on x86-64. The probe kept SIMD off on GCC older than 4.8, and the `HAVE_CPUID_H` guard broke builds that have `x86intrin.h` but not `cpuid.h` with a redefinition of `find_simd_implementation`.

https://github.com/ruby/json/commit/fae76b9eb4

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-15 07:01:06 +00:00
Hiroshi SHIBATAandClaude Opus 5.5 2f88a23ad0 json: Use SSE2 on x86-64 without checking at runtime
__builtin_cpu_supports refers to __cpu_model in compiler-rt, which clang-cl does not link, so generator.so and parser.so failed with an undefined symbol. SSE2 is part of the x86-64 baseline, as NEON is for AArch64, where no check is made either.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-15 13:39:04 +09:00
Hiroshi SHIBATAandClaude Opus 5.5 29ffa7a405 mkmf, extmk: Support GNU make on mswin
Run recipes with cmd.exe instead of /bin/sh, rewrite the nmake-style `$(VAR:/=\)` substitutions, which GNU make applies only to suffixes, and write the note on failed extensions in the form cmd.exe runs.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-15 08:00:21 +09:00
Douglas Eichelberger 44f7c6b00d Join getaddrinfo and getnameinfo threads before fork
A getaddrinfo thread calls getaddrinfo(3) inside rb_thread_prevent_fork,
but on glibc its thread exit takes the resolver configuration lock again
after the thread has released the fork lock. A fork that lands then
leaves the child with that lock held, and every later name lookup in the
child blocks forever. getnameinfo(3) attaches the same resolver state,
even for a name in /etc/hosts, and its thread ran outside
rb_thread_prevent_fork altogether.

Make the lookup threads joinable and have fork join any that may still
be exiting. As a lookup thread finishes, still inside
rb_thread_prevent_fork, it swaps itself into a single slot with an
atomic exchange and joins the thread it displaced, which has usually
exited by then, and rb_thread_acquire_fork_lock joins whatever is left
in the slot. Once lookups settle, at most one finished thread is left
unjoined. The slot holds pthread_t as a pointer, with NULL for empty,
which assumes pthread_t is scalar and never 0.

getnameinfo threads now run within rb_thread_prevent_fork and register
as they exit, as getaddrinfo threads do, and where getnameinfo runs
without a helper thread it is called within rb_thread_prevent_fork too.
So fork also waits for a reverse lookup in progress, as it already did
for a forward one. raddrinfo_pthread_create now always creates joinable
threads, which drops its pthread_detach fallback for platforms without
pthread_attr_setdetachstate.

The slot is kept across fork, so every fork path that keeps running
Ruby code has to take the fork lock. On the BSDs, Process.daemon forks
with daemon(3) and did not take it, so the daemon would inherit the
registered thread, and its next fork would abort in pthread_join with
ESRCH. Take and release the fork lock around daemon(3) as rb_fork_ruby
does. daemon(3) can fail in the child as well as in the parent, so
compare pids to tell which process returned.

[Bug #22406]
2026-10-14 10:46:00 +02:00
Kazuki Yamaguchi 1ec5306dc5 [ruby/openssl] ssl: align #putc with IO
Add the method. OpenSSL::Buffering already supports other
character-oriented methods such as #getc, #ungetc, or #readchar, and
this is the only missing method.

https://github.com/ruby/openssl/commit/df0fde6b4c
2026-10-13 16:29:31 +00:00
Kazuki Yamaguchi 15467f68cf [ruby/openssl] ssl: align #puts with IO
Handle nested arrays in the arguments, similar to how IO#puts behaves.

https://github.com/ruby/openssl/commit/d87ebfe0a1
2026-10-13 16:29:31 +00:00
Kazuki Yamaguchi 497f987ca5 [ruby/openssl] ssl: align #syswrite and #syswrite_nonblock with IO
IO#syswrite converts the argument with #to_s rather than #to_str.

https://github.com/ruby/openssl/commit/25a57af17f
2026-10-13 16:29:30 +00:00
Kazuki Yamaguchi ce8da0cfc0 [ruby/openssl] ssl: align #write and #<< with IO
IO#write and IO#<< convert the arguments to String with #to_s. RDoc
comments for OpenSSL::Buffering#write also stated this, but they do not
actually convert. Fix this.

OpenSSL::Buffering#puts and #print already correctly call #to_s.

https://github.com/ruby/openssl/commit/a801f1e957
2026-10-13 16:29:30 +00:00
Kazuki Yamaguchi f4a0d53e28 [ruby/openssl] ssl: align line-oriented methods with IO
Rewrite OpenSSL::Buffering#gets to handle parameters as closely to core
IO as possible. This includes changes:

  - Add support for gets(limit), where the rs parameter is omitted.
  - Add support for gets(nil, limit) (slurp mode).
  - Add support for gets("", limit) (paragraph mode).
  - Enforce limit correctly when EOF is reached before rs is found.
  - Do not attempt to read from the socket when limit=0 is passed.

Also let other line-oriented methods (#readline, #each_line, #each,
and #readlines) forward the limit argument to #gets.

https://github.com/ruby/openssl/commit/2e7b098d13
2026-10-13 16:29:29 +00:00
Kazuki Yamaguchi 6c87bfb282 [ruby/openssl] ssl: align #each_byte and #each_char with IO
Let OpenSSL::Buffering#each_byte return an Enumerator if called without
a block.

Also add the #each_char variant.

https://github.com/ruby/openssl/commit/0c6e84e8a1
2026-10-13 16:29:29 +00:00
Kazuki Yamaguchi 6750e8f01a [ruby/openssl] ssl: align #ungetc and #ungetbyte with IO
Passing a String to #ungetc should use the entire content, not just the
first character.

Also add OpenSSL::Buffering#ungetbyte for symmetry with IO#ungetbyte
which was added in Ruby 1.9.

https://github.com/ruby/openssl/commit/9a6d40138d
2026-10-13 16:29:29 +00:00
Kazuki Yamaguchi ee5f592185 [ruby/openssl] ssl: return mutable empty String
OpenSSL::SSLSocket#read, #read_nonblock, and #readpartial should return
a mutable String instead of literal "". This fixes a regression
introduced in v2.2.0 that added the frozen_string_literal magic comment
to this file.

https://github.com/ruby/openssl/commit/9d0ff3c5e3
2026-10-13 16:29:29 +00:00
Kazuki Yamaguchi fc929c894d [ruby/openssl] ssl: avoid subclassing String
Remove the internal Buffer class and instead use refinements to define
String#append_as_bytes when necessary.

This also fixes a few OpenSSL::Buffering methods leaking the internal
Buffer class through String#slice! on Ruby < 3.0.

https://github.com/ruby/openssl/commit/3b812dec30
2026-10-13 16:29:28 +00:00
Kazuki Yamaguchi 34cc07dfd1 [ruby/openssl] ssl: do not rescue Errno::EAGAIN
SSLSocket#sysread and #syswrite never raise Errno::EAGAIN.

It appears to me that commit https://github.com/ruby/ruby/commit/a9fb0817a154 (should wait for
that the underlying IO become readable or writable if the error was
SSL_ERROR_WANT_READ or SSL_ERROR_WANT_WRITE, 2005-03-05) made this
rescue unnecessary.

https://github.com/ruby/openssl/commit/bdc7867793
2026-10-13 15:41:55 +00:00
Jean Boussier 53e7d061f9 [ruby/json] Release 3.1.0
https://github.com/ruby/json/commit/a15b2ba603
2026-10-13 08:04:57 +00:00
Jean Boussier 72afd0b0d9 [ruby/json] Refactor rfc8785_sort_keys_proc
https://github.com/ruby/json/commit/d09e383d19
2026-10-13 07:32:24 +00:00
Hiroshi SHIBATAandClaude Opus 5.5 c83f90c682 [ruby/zlib] Return the full input length from Zlib::ZStream#avail_in
The int cast turned a remainder longer than INT_MAX into a wrong or negative number.

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

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-13 09:27:22 +09:00
Jean Boussier ad29ad7ad8 [ruby/json] Handle invalid encoding in JSON path keys
https://github.com/ruby/json/commit/e19f7d75a6
2026-10-12 14:55:31 +00:00
Jean Boussier 86f192cf38 [ruby/json] parser.c: only update the stack once fully spilled
https://github.com/ruby/json/commit/78d6a83a3c
2026-10-12 14:28:23 +00:00
Jean Boussier c5597ac4bd [ruby/json] Fix parsing of number with out of range negative exponents
https://github.com/ruby/json/commit/6ea62016fb
2026-10-12 14:22:32 +00:00
Jean Boussier 817023b888 [ruby/json] Fix parsing of unescaped NULL bytes in strings
https://github.com/ruby/json/commit/1b67eb3db2
2026-10-12 13:57:23 +00:00
Jean Boussier 90e7ab3ade [ruby/json] ResumableParser: fix handling of incomplete unicode escape
`spe` is the string end, so if the escape is incomplete, it doesn't
mean we reached the end of stream, hence it's a syntax error, not
an EOS error.

https://github.com/ruby/json/commit/c1a4372837
2026-10-12 13:51:08 +00:00
Tiago Cardoso 36f2a8e807 [Feature #13677] Add host to addrinfo resolution errors
hostname is added as a suffix to getaddrinfo error messages. for
example, a "name or service not known" error message becomes "name or
service not known for `invalidthost.com`.
2026-10-12 14:33:34 +02:00
Hiroshi SHIBATAandClaude Opus 5.5 a125858d48 [ruby/digest] Limit the hexencode and bubblebabble results by RB_LEN_MAX
The result is a String, whose length can exceed LONG_MAX on mswin.

https://github.com/ruby/digest/commit/de4c1f26d7

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-12 09:10:29 +00:00
Jean Boussier 0e01c2a87f [ruby/json] More hardening against adversarial encode methods
https://github.com/ruby/json/commit/429c109458
2026-10-12 08:15:47 +00:00
Hiroshi SHIBATAandClaude Opus 5.5 78a31f6735 [ruby/json] Index the generated JSON array by rb_len_t
An int index overflows on an Array longer than INT_MAX, which LP64 and now mswin can hold.

https://github.com/ruby/json/commit/8df32ab074

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-12 10:11:24 +02:00
Hiroshi SHIBATAandClaude Opus 5.5 3d73c09fa3 Keep the branch target count of the coverage cache as rb_len_t
LONG2FIX and FIX2LONG would narrow it to long once rb_len_t widens on mswin, where Fixnum is also only 31 bits.

https://bugs.ruby-lang.org/issues/22400

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-12 16:31:01 +09:00
ydah dbd87dcc28 [ruby/json] Sort RFC 8785 keys after as_json conversion
https://github.com/ruby/json/commit/88b358d8b2
2026-10-12 07:15:16 +00:00
Kazuki Yamaguchi 33120b353f [ruby/openssl] ssl: support SSLSocket#connect and #accept with timeout
Add a keyword argument timeout to specify the total time allowed for
the TLS handshake to complete. Inspired by Addrinfo#connect(timeout:)
and TCPSocket.open(connect_timeout:).

https://github.com/ruby/openssl/commit/3896e944b3
2026-10-11 06:28:01 +00:00