From b8201a09e026b3f2948a19eddf1341eb4b9668cf Mon Sep 17 00:00:00 2001 From: git Date: Sat, 27 Dec 2025 06:53:51 +0000 Subject: [PATCH 1/3] Update bundled gems list as of 2025-12-27 --- NEWS.md | 9 +++++++++ gems/bundled_gems | 4 ++-- 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/NEWS.md b/NEWS.md index 59a2b4b49d4c44..9712152da6a7b9 100644 --- a/NEWS.md +++ b/NEWS.md @@ -32,6 +32,15 @@ releases. ### The following bundled gems are updated. +* minitest 6.0.1 +* test-unit 3.7.6 +* rss 0.3.2 +* net-imap 0.6.2 +* typeprof 0.31.1 +* debug 1.11.1 +* mutex_m 0.3.0 +* rdoc 7.0.3 + ### RubyGems and Bundler Ruby 4.0 bundled RubyGems and Bundler version 4. see the following links for details. diff --git a/gems/bundled_gems b/gems/bundled_gems index 9461122e62dd73..f4afd8e9c27ac9 100644 --- a/gems/bundled_gems +++ b/gems/bundled_gems @@ -6,10 +6,10 @@ # - revision: revision in repository-url to test # if `revision` is not given, "v"+`version` or `version` will be used. -minitest 6.0.0 https://github.com/minitest/minitest +minitest 6.0.1 https://github.com/minitest/minitest power_assert 3.0.1 https://github.com/ruby/power_assert rake 13.3.1 https://github.com/ruby/rake -test-unit 3.7.5 https://github.com/test-unit/test-unit +test-unit 3.7.6 https://github.com/test-unit/test-unit rexml 3.4.4 https://github.com/ruby/rexml rss 0.3.2 https://github.com/ruby/rss net-ftp 0.3.9 https://github.com/ruby/net-ftp From 3c9e61f5ef8190e082b36e056f59be49692ae8aa Mon Sep 17 00:00:00 2001 From: Kazuki Yamaguchi Date: Sat, 27 Dec 2025 16:18:58 +0900 Subject: [PATCH 2/3] [ruby/openssl] cipher: remove incorrect assertion in Cipher#update Commit https://github.com/ruby/openssl/commit/1de3b80a46c2 (cipher: make output buffer String independent, 2024-12-10) ensures the output buffer String has sufficient capacity, bu the length can be shorter. The assert() is simply incorrect and should be removed. Also remove a similar assert() in Cipher#final. While not incorrect, it is not useful either. https://github.com/ruby/openssl/commit/0ce6ab97dd --- ext/openssl/ossl_cipher.c | 13 ++++++------- test/openssl/test_cipher.rb | 13 +++++++------ 2 files changed, 13 insertions(+), 13 deletions(-) diff --git a/ext/openssl/ossl_cipher.c b/ext/openssl/ossl_cipher.c index db65e99888d3bf..f3cd247c8fdfbc 100644 --- a/ext/openssl/ossl_cipher.c +++ b/ext/openssl/ossl_cipher.c @@ -401,9 +401,9 @@ ossl_cipher_update(int argc, VALUE *argv, VALUE self) } out_len = in_len + EVP_MAX_BLOCK_LENGTH; - if (NIL_P(str)) { - str = rb_str_new(0, out_len); - } else { + if (NIL_P(str)) + str = rb_str_buf_new(out_len); + else { StringValue(str); if ((long)rb_str_capacity(str) >= out_len) rb_str_modify(str); @@ -411,9 +411,9 @@ ossl_cipher_update(int argc, VALUE *argv, VALUE self) rb_str_modify_expand(str, out_len - RSTRING_LEN(str)); } - if (!ossl_cipher_update_long(ctx, (unsigned char *)RSTRING_PTR(str), &out_len, in, in_len)) - ossl_raise(eCipherError, NULL); - assert(out_len <= RSTRING_LEN(str)); + if (!ossl_cipher_update_long(ctx, (unsigned char *)RSTRING_PTR(str), + &out_len, in, in_len)) + ossl_raise(eCipherError, "EVP_CipherUpdate"); rb_str_set_len(str, out_len); return str; @@ -456,7 +456,6 @@ ossl_cipher_final(VALUE self) ossl_raise(eCipherError, "cipher final failed"); } } - assert(out_len <= RSTRING_LEN(str)); rb_str_set_len(str, out_len); return str; diff --git a/test/openssl/test_cipher.rb b/test/openssl/test_cipher.rb index 93766cfc88ce17..5b867671d312ad 100644 --- a/test/openssl/test_cipher.rb +++ b/test/openssl/test_cipher.rb @@ -134,13 +134,14 @@ def test_ctr_if_exists def test_update_with_buffer cipher = OpenSSL::Cipher.new("aes-128-ecb").encrypt cipher.random_key - expected = cipher.update("data") << cipher.final - assert_equal 16, expected.bytesize + expected = cipher.update("data" * 10) << cipher.final + assert_equal 48, expected.bytesize # Buffer is supplied cipher.reset buf = String.new - assert_same buf, cipher.update("data", buf) + assert_same buf, cipher.update("data" * 10, buf) + assert_equal 32, buf.bytesize assert_equal expected, buf + cipher.final # Buffer is frozen @@ -149,9 +150,9 @@ def test_update_with_buffer # Buffer is a shared string [ruby-core:120141] [Bug #20937] cipher.reset - buf = "x" * 1024 - shared = buf[-("data".bytesize + 32)..-1] - assert_same shared, cipher.update("data", shared) + buf = "x".b * 1024 + shared = buf[-("data".bytesize * 10 + 32)..-1] + assert_same shared, cipher.update("data" * 10, shared) assert_equal expected, shared + cipher.final end From a8c3d5e127776d74eb068c95610277feb99adcf0 Mon Sep 17 00:00:00 2001 From: Misaki Shioi <31817032+shioimm@users.noreply.github.com> Date: Sat, 27 Dec 2025 18:26:56 +0900 Subject: [PATCH 3/3] Fix: Do not fast_fallback if local_port is explicitly specified (#15732) `fast fallback` cannot be used with explicitly specified local port, because concurrent binds to the same `local_host:local_port` can raise `Errno::EADDRINUSE`. This issue is more likely to occur on hosts with `IPV6_V6ONLY` disabled, because IPv6 binds can also occupy IPv4-mapped IPv6 address space. --- ext/socket/ipsocket.c | 24 +++++++++++++++++++++--- ext/socket/lib/socket.rb | 5 ++--- 2 files changed, 23 insertions(+), 6 deletions(-) diff --git a/ext/socket/ipsocket.c b/ext/socket/ipsocket.c index e952b7871b3f6f..758d37293ffc2c 100644 --- a/ext/socket/ipsocket.c +++ b/ext/socket/ipsocket.c @@ -258,6 +258,22 @@ is_specified_ip_address(const char *hostname) inet_pton(AF_INET, hostname, &ipv4addr) == 1); } +static int +is_local_port_fixed(const char *portp) +{ + if (!portp) return 0; + + char *endp; + errno = 0; + long port = strtol(portp, &endp, 10); + + if (endp == portp) return 0; + if (errno == ERANGE) return 0; + if (port <= 0) return 0; + + return port != 0; +} + struct fast_fallback_inetsock_arg { VALUE self; @@ -1314,13 +1330,15 @@ rsock_init_inetsock( if (type == INET_CLIENT && FAST_FALLBACK_INIT_INETSOCK_IMPL == 1 && RTEST(fast_fallback)) { struct rb_addrinfo *local_res = NULL; - char *hostp, *portp; - char hbuf[NI_MAXHOST], pbuf[NI_MAXSERV]; + char *hostp, *portp, *local_portp; + char hbuf[NI_MAXHOST], pbuf[NI_MAXSERV], local_pbuf[NI_MAXSERV]; int additional_flags = 0; + int local_flags = 0; hostp = raddrinfo_host_str(remote_host, hbuf, sizeof(hbuf), &additional_flags); portp = raddrinfo_port_str(remote_serv, pbuf, sizeof(pbuf), &additional_flags); + local_portp = raddrinfo_port_str(local_serv, local_pbuf, sizeof(local_pbuf), &local_flags); - if (!is_specified_ip_address(hostp)) { + if (!is_specified_ip_address(hostp) && !is_local_port_fixed(local_portp)) { int target_families[2] = { 0, 0 }; int resolving_family_size = 0; diff --git a/ext/socket/lib/socket.rb b/ext/socket/lib/socket.rb index e74eaec43a3318..36fcceaee96300 100644 --- a/ext/socket/lib/socket.rb +++ b/ext/socket/lib/socket.rb @@ -660,12 +660,11 @@ def accept_nonblock(exception: true) # puts sock.read # } def self.tcp(host, port, local_host = nil, local_port = nil, connect_timeout: nil, resolv_timeout: nil, open_timeout: nil, fast_fallback: tcp_fast_fallback, &) # :yield: socket - if open_timeout && (connect_timeout || resolv_timeout) raise ArgumentError, "Cannot specify open_timeout along with connect_timeout or resolv_timeout" end - sock = if fast_fallback && !(host && ip_address?(host)) + sock = if fast_fallback && !(host && ip_address?(host)) && !(local_port && local_port.to_i != 0) tcp_with_fast_fallback(host, port, local_host, local_port, connect_timeout:, resolv_timeout:, open_timeout:) else tcp_without_fast_fallback(host, port, local_host, local_port, connect_timeout:, resolv_timeout:, open_timeout:) @@ -736,7 +735,7 @@ def self.tcp_with_fast_fallback(host, port, local_host = nil, local_port = nil, if local_addrinfos.any? local_addrinfo = local_addrinfos.find { |lai| lai.afamily == addrinfo.afamily } - if local_addrinfo.nil? # Connecting addrinfoと同じアドレスファミリのLocal addrinfoがない + if local_addrinfo.nil? if resolution_store.any_addrinfos? # Try other Addrinfo in next "while" next