Building the error message from a NULL pointer raised ArgumentError instead of IO::TimeoutError.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
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>
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>
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>
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>
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>
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>
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>
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
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>
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>
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>
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]
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>
__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>
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>
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]
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
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
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
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
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
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
`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
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`.
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