From da75893dbe4e6fbde84037a4e1730a95c685cdd9 Mon Sep 17 00:00:00 2001 From: Hiroshi SHIBATA Date: Wed, 5 Feb 2025 14:58:35 +0900 Subject: [PATCH 01/41] Bump up actions/upload-artifact-4.4.1 --- .github/workflows/wasm.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/wasm.yml b/.github/workflows/wasm.yml index f69df0f58d8bc0..543b7d963c1025 100644 --- a/.github/workflows/wasm.yml +++ b/.github/workflows/wasm.yml @@ -136,7 +136,7 @@ jobs: - run: tar cfz ../install.tar.gz -C ../install . - name: Upload artifacts - uses: actions/upload-artifact@a8a3f3ad30e3422c9c7b888a15615d19a852ae32 # v3.1.3 + uses: actions/upload-artifact@604373da6381bf24206979c74d06a550515601b9 # v4.4.1 with: name: ruby-wasm-install path: ${{ github.workspace }}/install.tar.gz From 84b60a03cd908c1b2efdfee65d71ffc03418ea21 Mon Sep 17 00:00:00 2001 From: Hiroshi SHIBATA Date: Wed, 5 Feb 2025 14:49:50 +0900 Subject: [PATCH 02/41] Bump up net-smtp-0.5.1 --- gems/bundled_gems | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gems/bundled_gems b/gems/bundled_gems index 806af42076e850..6de840d96fbe0a 100644 --- a/gems/bundled_gems +++ b/gems/bundled_gems @@ -14,7 +14,7 @@ rss 0.3.1 https://github.com/ruby/rss net-ftp 0.3.4 https://github.com/ruby/net-ftp net-imap 0.4.9.1 https://github.com/ruby/net-imap net-pop 0.1.2 https://github.com/ruby/net-pop -net-smtp 0.4.0.1 https://github.com/ruby/net-smtp +net-smtp 0.5.1 https://github.com/ruby/net-smtp matrix 0.4.2 https://github.com/ruby/matrix prime 0.1.2 https://github.com/ruby/prime rbs 3.4.0 https://github.com/ruby/rbs From 5b226fdb8df4a954476d8ee1b855539adaf82091 Mon Sep 17 00:00:00 2001 From: Hiroshi SHIBATA Date: Fri, 7 Feb 2025 11:02:42 +0900 Subject: [PATCH 03/41] Support `git ls-files ...`.split style for file list of gemspec --- tool/rbinstall.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tool/rbinstall.rb b/tool/rbinstall.rb index bb2e6a293c8d9d..029f358066bed4 100755 --- a/tool/rbinstall.rb +++ b/tool/rbinstall.rb @@ -980,7 +980,7 @@ def ensure_writable_dir(dir) def load_gemspec(file, base = nil) file = File.realpath(file) code = File.read(file, encoding: "utf-8:-") - code.gsub!(/(?:`git[^\`]*`|%x\[git[^\]]*\])\.split\([^\)]*\)/m) do + code.gsub!(/(?:`git[^\`]*`|%x\[git[^\]]*\])\.split(\([^\)]*\))?/m) do files = [] if base Dir.glob("**/*", File::FNM_DOTMATCH, base: base) do |n| From f8b9e2c06f04ea3720d94b5268b6c62e30ad3b26 Mon Sep 17 00:00:00 2001 From: "nicholas a. evans" Date: Tue, 11 Feb 2025 12:21:31 -0500 Subject: [PATCH 04/41] Bump net-imap to 0.4.19 for Ruby 3.3 (CVE-2025-25186) (#12732) This update addresses CVE-2025-25186 (GHSA-7fc5-f82f-cx69). --- gems/bundled_gems | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gems/bundled_gems b/gems/bundled_gems index 6de840d96fbe0a..40d79c6a3ccc8d 100644 --- a/gems/bundled_gems +++ b/gems/bundled_gems @@ -12,7 +12,7 @@ test-unit 3.6.1 https://github.com/test-unit/test-unit rexml 3.3.9 https://github.com/ruby/rexml rss 0.3.1 https://github.com/ruby/rss net-ftp 0.3.4 https://github.com/ruby/net-ftp -net-imap 0.4.9.1 https://github.com/ruby/net-imap +net-imap 0.4.19 https://github.com/ruby/net-imap net-pop 0.1.2 https://github.com/ruby/net-pop net-smtp 0.5.1 https://github.com/ruby/net-smtp matrix 0.4.2 https://github.com/ruby/matrix From 5eb08338ca318c3ea2e367f3b00f0d1fb36270e2 Mon Sep 17 00:00:00 2001 From: Takashi Kokubun Date: Thu, 13 Feb 2025 17:35:18 -0800 Subject: [PATCH 05/41] Drop k0kubun from CODEOWNERS The maintainers have been shifted to newer versions. https://bugs.ruby-lang.org/issues/21136 --- .github/CODEOWNERS | 1 - 1 file changed, 1 deletion(-) delete mode 100644 .github/CODEOWNERS diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS deleted file mode 100644 index d3650266bb602a..00000000000000 --- a/.github/CODEOWNERS +++ /dev/null @@ -1 +0,0 @@ -* @k0kubun From 2e7f65acbd52e9da57e7b2c44597106ca70aebd8 Mon Sep 17 00:00:00 2001 From: Hiroshi SHIBATA Date: Fri, 28 Feb 2025 15:54:12 +0900 Subject: [PATCH 06/41] Skip VS2022 17.13.x build see https://github.com/ruby/ruby/pull/12830 --- .github/workflows/windows.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/windows.yml b/.github/workflows/windows.yml index 8b34f962fec6f3..8f5625c57a7a4a 100644 --- a/.github/workflows/windows.yml +++ b/.github/workflows/windows.yml @@ -38,7 +38,7 @@ jobs: matrix: include: - vs: 2019 - - vs: 2022 + # - vs: 2022 fail-fast: false runs-on: windows-${{ matrix.vs < 2022 && '2019' || matrix.vs }} From c462deb48262eeb4dc08255d9b859eb73759eb95 Mon Sep 17 00:00:00 2001 From: Takashi Kokubun Date: Wed, 5 Mar 2025 15:34:37 -0800 Subject: [PATCH 07/41] Update actions/cache for ruby_3_3 --- .github/actions/setup/directories/action.yml | 2 +- .github/workflows/windows.yml | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/actions/setup/directories/action.yml b/.github/actions/setup/directories/action.yml index 359e5c0d37ce38..4150288ed77084 100644 --- a/.github/actions/setup/directories/action.yml +++ b/.github/actions/setup/directories/action.yml @@ -80,7 +80,7 @@ runs: with: path: ${{ inputs.srcdir }} - - uses: actions/cache@88522ab9f39a2ea568f7027eddc7d8d8bc9d59c8 # v3.3.1 + - uses: actions/cache@0c907a75c2c80ebcb7f088228285e798b750cf8f # v4.2.1 with: path: ${{ inputs.srcdir }}/.downloaded-cache key: downloaded-cache diff --git a/.github/workflows/windows.yml b/.github/workflows/windows.yml index 8f5625c57a7a4a..fc936ae91f76db 100644 --- a/.github/workflows/windows.yml +++ b/.github/workflows/windows.yml @@ -93,7 +93,7 @@ jobs: ${{ steps.find-tools.outputs.needs }} if: ${{ steps.find-tools.outputs.needs != '' }} - - uses: actions/cache@704facf57e6136b1bc63b828d79edcd491f0ee84 # v3.3.2 + - uses: actions/cache@0c907a75c2c80ebcb7f088228285e798b750cf8f # v4.2.1 with: path: C:\vcpkg\downloads key: ${{ runner.os }}-vcpkg-download-${{ env.OS_VER }}-${{ github.sha }} @@ -101,7 +101,7 @@ jobs: ${{ runner.os }}-vcpkg-download-${{ env.OS_VER }}- ${{ runner.os }}-vcpkg-download- - - uses: actions/cache@704facf57e6136b1bc63b828d79edcd491f0ee84 # v3.3.2 + - uses: actions/cache@0c907a75c2c80ebcb7f088228285e798b750cf8f # v4.2.1 with: path: C:\vcpkg\installed key: ${{ runner.os }}-vcpkg-installed-${{ env.OS_VER }}-${{ github.sha }} From 9472548aa1b8b82515602e543ec03872d0b139cb Mon Sep 17 00:00:00 2001 From: Hiroshi SHIBATA Date: Thu, 22 Aug 2024 09:47:13 +0900 Subject: [PATCH 08/41] automerge needs windows results --- .github/workflows/windows.yml | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/.github/workflows/windows.yml b/.github/workflows/windows.yml index fc936ae91f76db..6311854e256047 100644 --- a/.github/workflows/windows.yml +++ b/.github/workflows/windows.yml @@ -195,6 +195,16 @@ jobs: SLACK_WEBHOOK_URL: ${{ secrets.SIMPLER_ALERTS_URL }} # ruby-lang slack: ruby/simpler-alerts-bot if: ${{ failure() }} + result: + if: ${{ always() }} + name: ${{ github.workflow }} result + runs-on: windows-latest + needs: [make] + steps: + - run: exit 1 + working-directory: + if: ${{ contains(needs.*.result, 'failure') || contains(needs.*.result, 'cancelled') }} + defaults: run: working-directory: build From 188ff4d4356b1a369e2204e5c45e1d168ffdf631 Mon Sep 17 00:00:00 2001 From: Nobuyoshi Nakada Date: Tue, 5 Nov 2024 18:04:19 +0900 Subject: [PATCH 09/41] Name dependency checks job And run on the latest ubuntu. --- .github/workflows/check_dependencies.yml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.github/workflows/check_dependencies.yml b/.github/workflows/check_dependencies.yml index 10c202c3c132a2..37b993514685af 100644 --- a/.github/workflows/check_dependencies.yml +++ b/.github/workflows/check_dependencies.yml @@ -34,9 +34,11 @@ permissions: jobs: update-deps: + name: Dependency checks + strategy: matrix: - os: [ubuntu-20.04] + os: [ubuntu-latest] fail-fast: true runs-on: ${{ matrix.os }} From e58827163002e816e49ed18007f4fa3481102b08 Mon Sep 17 00:00:00 2001 From: Hiroshi SHIBATA Date: Wed, 26 Feb 2025 18:14:16 +0900 Subject: [PATCH 10/41] Merge uri-0.13.2 --- lib/uri/generic.rb | 15 +++++++-------- lib/uri/version.rb | 2 +- test/uri/test_generic.rb | 18 ++++++++++++++++++ 3 files changed, 26 insertions(+), 9 deletions(-) diff --git a/lib/uri/generic.rb b/lib/uri/generic.rb index f3540a24bb7de8..2c0a88da5dae3c 100644 --- a/lib/uri/generic.rb +++ b/lib/uri/generic.rb @@ -1133,17 +1133,16 @@ def merge(oth) base.fragment=(nil) # RFC2396, Section 5.2, 4) - if !authority - base.set_path(merge_path(base.path, rel.path)) if base.path && rel.path - else - # RFC2396, Section 5.2, 4) - base.set_path(rel.path) if rel.path + if authority + base.set_userinfo(rel.userinfo) + base.set_host(rel.host) + base.set_port(rel.port || base.default_port) + base.set_path(rel.path) + elsif base.path && rel.path + base.set_path(merge_path(base.path, rel.path)) end # RFC2396, Section 5.2, 7) - base.set_userinfo(rel.userinfo) if rel.userinfo - base.set_host(rel.host) if rel.host - base.set_port(rel.port) if rel.port base.query = rel.query if rel.query base.fragment=(rel.fragment) if rel.fragment diff --git a/lib/uri/version.rb b/lib/uri/version.rb index bfe3f476708714..962f09a3e6470a 100644 --- a/lib/uri/version.rb +++ b/lib/uri/version.rb @@ -1,6 +1,6 @@ module URI # :stopdoc: - VERSION_CODE = '001301'.freeze + VERSION_CODE = '001302'.freeze VERSION = VERSION_CODE.scan(/../).collect{|n| n.to_i}.join('.').freeze # :startdoc: end diff --git a/test/uri/test_generic.rb b/test/uri/test_generic.rb index e6619373c65d4a..1a70dd42c42ed3 100644 --- a/test/uri/test_generic.rb +++ b/test/uri/test_generic.rb @@ -164,6 +164,17 @@ def test_parse # must be empty string to identify as path-abempty, not path-absolute assert_equal('', url.host) assert_equal('http:////example.com', url.to_s) + + # sec-2957667 + url = URI.parse('http://user:pass@example.com').merge('//example.net') + assert_equal('http://example.net', url.to_s) + assert_nil(url.userinfo) + url = URI.join('http://user:pass@example.com', '//example.net') + assert_equal('http://example.net', url.to_s) + assert_nil(url.userinfo) + url = URI.parse('http://user:pass@example.com') + '//example.net' + assert_equal('http://example.net', url.to_s) + assert_nil(url.userinfo) end def test_parse_scheme_with_symbols @@ -256,6 +267,13 @@ def test_merge assert_equal(u0, u1) end + def test_merge_authority + u = URI.parse('http://user:pass@example.com:8080') + u0 = URI.parse('http://new.example.org/path') + u1 = u.merge('//new.example.org/path') + assert_equal(u0, u1) + end + def test_route url = URI.parse('http://hoge/a.html').route_to('http://hoge/b.html') assert_equal('b.html', url.to_s) From ecb9f7ef372c70c3e4fa81a5002533814a94aa86 Mon Sep 17 00:00:00 2001 From: Hiroshi SHIBATA Date: Wed, 26 Feb 2025 18:14:54 +0900 Subject: [PATCH 11/41] Merge cgi-0.4.2 --- lib/cgi.rb | 2 +- lib/cgi/cgi.gemspec | 3 ++- lib/cgi/cookie.rb | 5 +++-- lib/cgi/session/pstore.rb | 7 +++++-- lib/cgi/util.rb | 4 ++-- test/cgi/test_cgi_session.rb | 2 +- test/cgi/test_cgi_util.rb | 18 ++++++++++++++++++ 7 files changed, 32 insertions(+), 9 deletions(-) diff --git a/lib/cgi.rb b/lib/cgi.rb index 7af85e7fc85e3d..69c3c4fd244d5e 100644 --- a/lib/cgi.rb +++ b/lib/cgi.rb @@ -288,7 +288,7 @@ # class CGI - VERSION = "0.4.1" + VERSION = "0.4.2" end require 'cgi/core' diff --git a/lib/cgi/cgi.gemspec b/lib/cgi/cgi.gemspec index 381c55a5caeaea..5ef00d591de6ef 100644 --- a/lib/cgi/cgi.gemspec +++ b/lib/cgi/cgi.gemspec @@ -25,7 +25,8 @@ Gem::Specification.new do |spec| spec.executables = [] spec.files = [ - "LICENSE.txt", + "COPYING", + "BSDL", "README.md", *Dir["lib{.rb,/**/*.rb}", "bin/*"] ] diff --git a/lib/cgi/cookie.rb b/lib/cgi/cookie.rb index 9498e2f9faf9f7..1c4ef6a600ef9a 100644 --- a/lib/cgi/cookie.rb +++ b/lib/cgi/cookie.rb @@ -190,9 +190,10 @@ def self.parse(raw_cookie) values ||= "" values = values.split('&').collect{|v| CGI.unescape(v,@@accept_charset) } if cookies.has_key?(name) - values = cookies[name].value + values + cookies[name].concat(values) + else + cookies[name] = Cookie.new(name, *values) end - cookies[name] = Cookie.new(name, *values) end cookies diff --git a/lib/cgi/session/pstore.rb b/lib/cgi/session/pstore.rb index 45d0d8ae2cb17b..6e3d10f0751226 100644 --- a/lib/cgi/session/pstore.rb +++ b/lib/cgi/session/pstore.rb @@ -11,7 +11,10 @@ # cgi/session.rb for more details on session storage managers. require_relative '../session' -require 'pstore' +begin + require 'pstore' +rescue LoadError +end class CGI class Session @@ -82,7 +85,7 @@ def delete File::unlink path end - end + end if defined?(::PStore) end end # :enddoc: diff --git a/lib/cgi/util.rb b/lib/cgi/util.rb index 4986e544e01444..5f12eae1302963 100644 --- a/lib/cgi/util.rb +++ b/lib/cgi/util.rb @@ -184,7 +184,7 @@ def unescapeHTML(string) def escapeElement(string, *elements) elements = elements[0] if elements[0].kind_of?(Array) unless elements.empty? - string.gsub(/<\/?(?:#{elements.join("|")})(?!\w)(?:.|\n)*?>/i) do + string.gsub(/<\/?(?:#{elements.join("|")})\b[^<>]*+>?/im) do CGI.escapeHTML($&) end else @@ -204,7 +204,7 @@ def escapeElement(string, *elements) def unescapeElement(string, *elements) elements = elements[0] if elements[0].kind_of?(Array) unless elements.empty? - string.gsub(/<\/?(?:#{elements.join("|")})(?!\w)(?:.|\n)*?>/i) do + string.gsub(/<\/?(?:#{elements.join("|")})\b(?>[^&]+|&(?![gl]t;)\w+;)*(?:>)?/im) do unescapeHTML($&) end else diff --git a/test/cgi/test_cgi_session.rb b/test/cgi/test_cgi_session.rb index b16b69766e910f..32b907d741214d 100644 --- a/test/cgi/test_cgi_session.rb +++ b/test/cgi/test_cgi_session.rb @@ -91,7 +91,7 @@ def test_cgi_session_pstore assert_equal(value1,session["key1"]) assert_equal(value2,session["key2"]) session.close - end + end if defined?(::PStore) def test_cgi_session_specify_session_id update_env( 'REQUEST_METHOD' => 'GET', diff --git a/test/cgi/test_cgi_util.rb b/test/cgi/test_cgi_util.rb index b0612fc87d9035..bff77f7ffcecd5 100644 --- a/test/cgi/test_cgi_util.rb +++ b/test/cgi/test_cgi_util.rb @@ -269,6 +269,14 @@ def test_cgi_escapeElement assert_equal("
<A HREF="url"></A>", escapeElement('
', ["A", "IMG"])) assert_equal("
<A HREF="url"></A>", escape_element('
', "A", "IMG")) assert_equal("
<A HREF="url"></A>", escape_element('
', ["A", "IMG"])) + + assert_equal("<A <A HREF="url"></A>", escapeElement('', "A", "IMG")) + assert_equal("<A <A HREF="url"></A>", escapeElement('', ["A", "IMG"])) + assert_equal("<A <A HREF="url"></A>", escape_element('', "A", "IMG")) + assert_equal("<A <A HREF="url"></A>", escape_element('', ["A", "IMG"])) + + assert_equal("<A <A ", escapeElement('', unescapeElement(escapeHTML('
'), ["A", "IMG"])) assert_equal('<BR>', unescape_element(escapeHTML('
'), "A", "IMG")) assert_equal('<BR>', unescape_element(escapeHTML('
'), ["A", "IMG"])) + + assert_equal('', unescapeElement(escapeHTML(''), "A", "IMG")) + assert_equal('', unescapeElement(escapeHTML(''), ["A", "IMG"])) + assert_equal('', unescape_element(escapeHTML(''), "A", "IMG")) + assert_equal('', unescape_element(escapeHTML(''), ["A", "IMG"])) + + assert_equal(' Date: Wed, 5 Mar 2025 14:21:48 -0800 Subject: [PATCH 12/41] Replace tombstone when converting AR to ST hash [Bug #21170] st_table reserves -1 as a special hash value to indicate that an entry has been deleted. So that that's a valid value to be returned from the hash function, do_hash replaces -1 with 0 so that it is not mistaken for the sentinel. Previously, when upgrading an AR table to an ST table, rb_st_add_direct_with_hash was used which did not perform the same conversion, this could lead to a hash in a broken state where one if its entries which was supposed to exist being marked as a tombstone. The hash could then become further corrupted when the ST table required resizing as the falsely tombstoned entry would be skipped but it would be counted in num entries, leading to an uninitialized entry at index 15. In most cases this will be really rare, unless using a very poorly implemented custom hash function. This also adds two debug assertions, one that st_add_direct_with_hash does not receive the reserved hash value, and a second in rebuild_table_with, which ensures that after we rebuild/compact a table it contains the expected number of elements. Co-authored-by: Alan Wu --- common.mk | 1 + st.c | 23 +++++++++++++++++------ test/ruby/test_hash.rb | 14 ++++++++++++++ 3 files changed, 32 insertions(+), 6 deletions(-) diff --git a/common.mk b/common.mk index 70b66b11f411f0..fe8c5ed74349fd 100644 --- a/common.mk +++ b/common.mk @@ -16956,6 +16956,7 @@ st.$(OBJEXT): {$(VPATH)}internal/variable.h st.$(OBJEXT): {$(VPATH)}internal/warning_push.h st.$(OBJEXT): {$(VPATH)}internal/xmalloc.h st.$(OBJEXT): {$(VPATH)}missing.h +st.$(OBJEXT): {$(VPATH)}ruby_assert.h st.$(OBJEXT): {$(VPATH)}st.c st.$(OBJEXT): {$(VPATH)}st.h st.$(OBJEXT): {$(VPATH)}subst.h diff --git a/st.c b/st.c index b921b1bf3ba5af..50bfd4bfbb4e42 100644 --- a/st.c +++ b/st.c @@ -103,11 +103,13 @@ #ifdef NOT_RUBY #include "regint.h" #include "st.h" +#include #elif defined RUBY_EXPORT #include "internal.h" #include "internal/bits.h" #include "internal/hash.h" #include "internal/sanitizers.h" +#include "ruby_assert.h" #endif #include @@ -115,7 +117,6 @@ #include #endif #include -#include #ifdef __GNUC__ #define PREFETCH(addr, write_p) __builtin_prefetch(addr, write_p) @@ -313,17 +314,22 @@ static const struct st_features features[] = { #define RESERVED_HASH_VAL (~(st_hash_t) 0) #define RESERVED_HASH_SUBSTITUTION_VAL ((st_hash_t) 0) -/* Return hash value of KEY for table TAB. */ static inline st_hash_t -do_hash(st_data_t key, st_table *tab) +normalize_hash_value(st_hash_t hash) { - st_hash_t hash = (st_hash_t)(tab->type->hash)(key); - /* RESERVED_HASH_VAL is used for a deleted entry. Map it into another value. Such mapping should be extremely rare. */ return hash == RESERVED_HASH_VAL ? RESERVED_HASH_SUBSTITUTION_VAL : hash; } +/* Return hash value of KEY for table TAB. */ +static inline st_hash_t +do_hash(st_data_t key, st_table *tab) +{ + st_hash_t hash = (st_hash_t)(tab->type->hash)(key); + return normalize_hash_value(hash); +} + /* Power of 2 defining the minimal number of allocated entries. */ #define MINIMAL_POWER2 2 @@ -779,6 +785,9 @@ rebuild_table_with(st_table *new_tab, st_table *tab) new_tab->num_entries++; ni++; } + + assert(new_tab->num_entries == tab->num_entries); + if (new_tab != tab) { tab->entry_power = new_tab->entry_power; tab->bin_power = new_tab->bin_power; @@ -1160,6 +1169,8 @@ st_add_direct_with_hash(st_table *tab, st_index_t ind; st_index_t bin_ind; + assert(hash != RESERVED_HASH_VAL); + rebuild_table_if_necessary(tab); ind = tab->entries_bound++; entry = &tab->entries[ind]; @@ -1177,7 +1188,7 @@ void rb_st_add_direct_with_hash(st_table *tab, st_data_t key, st_data_t value, st_hash_t hash) { - st_add_direct_with_hash(tab, key, value, hash); + st_add_direct_with_hash(tab, key, value, normalize_hash_value(hash)); } /* Insert (KEY, VALUE) into table TAB. The table should not have diff --git a/test/ruby/test_hash.rb b/test/ruby/test_hash.rb index a063518190e869..2d36556953ab3b 100644 --- a/test/ruby/test_hash.rb +++ b/test/ruby/test_hash.rb @@ -2352,4 +2352,18 @@ def hash end end; end + + def test_ar_to_st_reserved_value + klass = Class.new do + attr_reader :hash + def initialize(val) = @hash = val + end + + values = 0.downto(-16).to_a + hash = {} + values.each do |val| + hash[klass.new(val)] = val + end + assert_equal values, hash.values, "[ruby-core:121239] [Bug #21170]" + end end From 56ba9041d9e338359b32ba0bfb3d816d57dc9d39 Mon Sep 17 00:00:00 2001 From: nagachika Date: Sat, 8 Mar 2025 17:03:20 +0900 Subject: [PATCH 13/41] merge revision(s) ae6bd3b49ba252985b92416c24102ede3c0aac9b, 966458199d870b88b42898d4a063b487c1ef6b00, 966458199d870b88b42898d4a063b487c1ef6b00: [Backport #20951] [DOC] Tweak "Timezone Objects" - Make method descriptions plain pragraphs in each method. - Make "Argument" and "Returns" note-lists. [Bug #20951] [DOC] About UTC offset calculation after `utc_to_local` [Bug #20951] [DOC] About UTC offset calculation after `utc_to_local` --- doc/_timezones.rdoc | 50 +++++++++++++++++++++++++-------------------- version.h | 2 +- 2 files changed, 29 insertions(+), 23 deletions(-) diff --git a/doc/_timezones.rdoc b/doc/_timezones.rdoc index c5230ea67dd9fd..e355d699b47a53 100644 --- a/doc/_timezones.rdoc +++ b/doc/_timezones.rdoc @@ -64,43 +64,49 @@ The timezone methods are: - +local_to_utc+: - - Called when Time.new is invoked with +tz+ - as the value of positional argument +zone+ or keyword argument +in:+. - - Argument: a {Time-like object}[rdoc-ref:Time@Time-Like+Objects]. - - Returns: a {Time-like object}[rdoc-ref:Time@Time-Like+Objects] in the UTC timezone. + Called when Time.new is invoked with +tz+ as the value of positional + argument +zone+ or keyword argument +in:+. + + Argument:: a {Time-like object}[rdoc-ref:Time@Time-Like+Objects]. + Returns:: a {Time-like object}[rdoc-ref:Time@Time-Like+Objects] in the UTC timezone. - +utc_to_local+: - - Called when Time.at or Time.now is invoked with +tz+ - as the value for keyword argument +in:+, - and when Time#getlocal or Time#localtime is called with +tz+ - as the value for positional argument +zone+. - - Argument: a {Time-like object}[rdoc-ref:Time@Time-Like+Objects]. - - Returns: a {Time-like object}[rdoc-ref:Time@Time-Like+Objects] in the local timezone. + Called when Time.at or Time.now is invoked with +tz+ as the value for + keyword argument +in:+, and when Time#getlocal or Time#localtime is called + with +tz+ as the value for positional argument +zone+. + + The UTC offset will be calculated as the difference between the + original time and the returned object as an +Integer+. + + Argument:: a {Time-like object}[rdoc-ref:Time@Time-Like+Objects]. + Returns:: a {Time-like object}[rdoc-ref:Time@Time-Like+Objects] in the local timezone. A custom timezone class may have these instance methods, which will be called if defined: - +abbr+: - - Called when Time#strftime is invoked with a format involving %Z. - - Argument: a {Time-like object}[rdoc-ref:Time@Time-Like+Objects]. - - Returns: a string abbreviation for the timezone name. + Called when Time#strftime is invoked with a format involving %Z. + + Argument:: a {Time-like object}[rdoc-ref:Time@Time-Like+Objects]. + Returns:: a string abbreviation for the timezone name. - +dst?+: - - Called when Time.at or Time.now is invoked with +tz+ - as the value for keyword argument +in:+, - and when Time#getlocal or Time#localtime is called with +tz+ - as the value for positional argument +zone+. - - Argument: a {Time-like object}[rdoc-ref:Time@Time-Like+Objects]. - - Returns: whether the time is daylight saving time. + Called when Time.at or Time.now is invoked with +tz+ as the value for + keyword argument +in:+, and when Time#getlocal or Time#localtime is + called with +tz+ as the value for positional argument +zone+. + + Argument:: a {Time-like object}[rdoc-ref:Time@Time-Like+Objects]. + Returns:: whether the time is daylight saving time. - +name+: - - Called when Marshal.dump(t) is invoked - - Argument: none. - - Returns: the string name of the timezone. + Called when Marshal.dump(t) is invoked + + Argument:: none. + Returns:: the string name of the timezone. ==== +Time+-Like Objects diff --git a/version.h b/version.h index cddd5935ff57cc..9cc5f3bb4f7df8 100644 --- a/version.h +++ b/version.h @@ -11,7 +11,7 @@ # define RUBY_VERSION_MINOR RUBY_API_VERSION_MINOR #define RUBY_VERSION_TEENY 7 #define RUBY_RELEASE_DATE RUBY_RELEASE_YEAR_STR"-"RUBY_RELEASE_MONTH_STR"-"RUBY_RELEASE_DAY_STR -#define RUBY_PATCHLEVEL 123 +#define RUBY_PATCHLEVEL 124 #include "ruby/version.h" #include "ruby/internal/abi.h" From 8274b8193e0a047d1edfff603dd2436276f906c4 Mon Sep 17 00:00:00 2001 From: nagachika Date: Sat, 8 Mar 2025 17:23:15 +0900 Subject: [PATCH 14/41] merge revision(s) f7059af50a31a4d27a04ace0beadb60616f3f971: [Backport #21046] Use no-inline version `rb_current_ec` on Arm64 The TLS across .so issue seems related to Arm64, but not Darwin. --- thread_pthread.h | 4 ++-- version.h | 2 +- vm.c | 2 +- vm_core.h | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/thread_pthread.h b/thread_pthread.h index 20c4b9f9a835b6..a10e788950b9a0 100644 --- a/thread_pthread.h +++ b/thread_pthread.h @@ -132,8 +132,8 @@ struct rb_thread_sched { NOINLINE(void rb_current_ec_set(struct rb_execution_context_struct *)); NOINLINE(struct rb_execution_context_struct *rb_current_ec_noinline(void)); - # ifdef __APPLE__ - // on Darwin, TLS can not be accessed across .so + # if defined(__arm64__) || defined(__aarch64__) + // on Arm64, TLS can not be accessed across .so NOINLINE(struct rb_execution_context_struct *rb_current_ec(void)); # else RUBY_EXTERN RB_THREAD_LOCAL_SPECIFIER struct rb_execution_context_struct *ruby_current_ec; diff --git a/version.h b/version.h index 9cc5f3bb4f7df8..fc992a83b00cd8 100644 --- a/version.h +++ b/version.h @@ -11,7 +11,7 @@ # define RUBY_VERSION_MINOR RUBY_API_VERSION_MINOR #define RUBY_VERSION_TEENY 7 #define RUBY_RELEASE_DATE RUBY_RELEASE_YEAR_STR"-"RUBY_RELEASE_MONTH_STR"-"RUBY_RELEASE_DAY_STR -#define RUBY_PATCHLEVEL 124 +#define RUBY_PATCHLEVEL 125 #include "ruby/version.h" #include "ruby/internal/abi.h" diff --git a/vm.c b/vm.c index a0fe0104b0dc52..62ea5be53b6f27 100644 --- a/vm.c +++ b/vm.c @@ -551,7 +551,7 @@ rb_current_ec_set(rb_execution_context_t *ec) } -#ifdef __APPLE__ +#if defined(__arm64__) || defined(__aarch64__) rb_execution_context_t * rb_current_ec(void) { diff --git a/vm_core.h b/vm_core.h index 30bfb8404acfb2..c29791a6c46d24 100644 --- a/vm_core.h +++ b/vm_core.h @@ -1930,7 +1930,7 @@ static inline rb_execution_context_t * rb_current_execution_context(bool expect_ec) { #ifdef RB_THREAD_LOCAL_SPECIFIER - #ifdef __APPLE__ + #if defined(__arm64__) || defined(__aarch64__) rb_execution_context_t *ec = rb_current_ec(); #else rb_execution_context_t *ec = ruby_current_ec; From 54dd27d89d2e6814114f1aff18836a987d5a4ab1 Mon Sep 17 00:00:00 2001 From: nagachika Date: Sat, 8 Mar 2025 17:26:28 +0900 Subject: [PATCH 15/41] merge revision(s) d4a1a2780c39bc648496ac92fc6e6ce2eb38ab47: [Backport #21032] rb_feature_p: skip `get_expanded_load_path` for absolute paths Ref: https://github.com/fxn/zeitwerk/pull/308 ```ruby require 'benchmark' $LOAD_PATH << 'relative-path' autoload :FOO, '/tmp/foo.rb' puts Benchmark.realtime { 500_000.times do Object.autoload?(:FOO) end } ``` The above script takes 2.5 seconds on `master`, and only 50ms on this branch. When we're looking for a feature with an absolute path, we don't need to call the expensive `get_expanded_load_path`. --- load.c | 2 +- version.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/load.c b/load.c index d962d08b37fbae..721a331ced9e12 100644 --- a/load.c +++ b/load.c @@ -596,7 +596,7 @@ rb_feature_p(rb_vm_t *vm, const char *feature, const char *ext, int rb, int expa loading_tbl = get_loading_table(vm); f = 0; - if (!expanded) { + if (!expanded && !rb_is_absolute_path(feature)) { struct loaded_feature_searching fs; fs.name = feature; fs.len = len; diff --git a/version.h b/version.h index fc992a83b00cd8..6065964a686c4f 100644 --- a/version.h +++ b/version.h @@ -11,7 +11,7 @@ # define RUBY_VERSION_MINOR RUBY_API_VERSION_MINOR #define RUBY_VERSION_TEENY 7 #define RUBY_RELEASE_DATE RUBY_RELEASE_YEAR_STR"-"RUBY_RELEASE_MONTH_STR"-"RUBY_RELEASE_DAY_STR -#define RUBY_PATCHLEVEL 125 +#define RUBY_PATCHLEVEL 126 #include "ruby/version.h" #include "ruby/internal/abi.h" From fff5baf200572762a60c624bc7bea866992c2f30 Mon Sep 17 00:00:00 2001 From: nagachika Date: Sat, 8 Mar 2025 18:19:14 +0900 Subject: [PATCH 16/41] merge revision(s) 46b544c54955348ef1ea9692b837b061f59f91cd, d3abee739f4feb91bb9aaae33877d70c8c576db0: [Backport #21095] Prefer `uname -n` over `hostname`. (#12647) Add fallback for `hostname` if `uname` isn't available. (#12655) --- spec/ruby/library/socket/socket/gethostname_spec.rb | 10 +++++++++- version.h | 2 +- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/spec/ruby/library/socket/socket/gethostname_spec.rb b/spec/ruby/library/socket/socket/gethostname_spec.rb index 4b79747b2721e5..89e1ed496f10b0 100644 --- a/spec/ruby/library/socket/socket/gethostname_spec.rb +++ b/spec/ruby/library/socket/socket/gethostname_spec.rb @@ -2,7 +2,15 @@ require_relative '../fixtures/classes' describe "Socket.gethostname" do + def system_hostname + # Most platforms implement this POSIX standard: + `uname -n`.strip + rescue + # Only really required for Windows without MSYS/MinGW/Cygwin etc: + `hostname`.strip + end + it "returns the host name" do - Socket.gethostname.should == `hostname`.strip + Socket.gethostname.should == system_hostname end end diff --git a/version.h b/version.h index 6065964a686c4f..2c823ebf70be6c 100644 --- a/version.h +++ b/version.h @@ -11,7 +11,7 @@ # define RUBY_VERSION_MINOR RUBY_API_VERSION_MINOR #define RUBY_VERSION_TEENY 7 #define RUBY_RELEASE_DATE RUBY_RELEASE_YEAR_STR"-"RUBY_RELEASE_MONTH_STR"-"RUBY_RELEASE_DAY_STR -#define RUBY_PATCHLEVEL 126 +#define RUBY_PATCHLEVEL 127 #include "ruby/version.h" #include "ruby/internal/abi.h" From e860cb2267cd17aef9a5e8e977d03410c213d6a2 Mon Sep 17 00:00:00 2001 From: nagachika Date: Sat, 8 Mar 2025 18:21:16 +0900 Subject: [PATCH 17/41] merge revision(s) 91a10c07579f282a94e4b5830feaeca87f9a7dd3: [Backport #21112] Fix a typo in WeakKeyMap argument error [Bug #21112] --- version.h | 2 +- weakmap.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/version.h b/version.h index 2c823ebf70be6c..1623f73fdf6ec3 100644 --- a/version.h +++ b/version.h @@ -11,7 +11,7 @@ # define RUBY_VERSION_MINOR RUBY_API_VERSION_MINOR #define RUBY_VERSION_TEENY 7 #define RUBY_RELEASE_DATE RUBY_RELEASE_YEAR_STR"-"RUBY_RELEASE_MONTH_STR"-"RUBY_RELEASE_DAY_STR -#define RUBY_PATCHLEVEL 127 +#define RUBY_PATCHLEVEL 128 #include "ruby/version.h" #include "ruby/internal/abi.h" diff --git a/weakmap.c b/weakmap.c index 8b6b46715b94e9..f699853439c318 100644 --- a/weakmap.c +++ b/weakmap.c @@ -843,7 +843,7 @@ wkmap_aset(VALUE self, VALUE key, VALUE val) TypedData_Get_Struct(self, struct weakkeymap, &weakkeymap_type, w); if (!FL_ABLE(key) || SYMBOL_P(key) || RB_BIGNUM_TYPE_P(key) || RB_TYPE_P(key, T_FLOAT)) { - rb_raise(rb_eArgError, "WeakKeyMap must be garbage collectable"); + rb_raise(rb_eArgError, "WeakKeyMap keys must be garbage collectable"); UNREACHABLE_RETURN(Qnil); } From ac3f355fb33f4ce41df864f2084028610b7b38d1 Mon Sep 17 00:00:00 2001 From: nagachika Date: Sun, 16 Mar 2025 13:10:13 +0900 Subject: [PATCH 18/41] Silently ignore keyword args for attr-asign method to cease segmentation fault. --- compile.c | 3 ++- version.h | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/compile.c b/compile.c index f9738867b727b9..110530f89f3c4a 100644 --- a/compile.c +++ b/compile.c @@ -9666,6 +9666,7 @@ compile_attrasgn(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node VALUE argc; LABEL *else_label = NULL; VALUE branches = Qfalse; + struct rb_callinfo_kwarg *keywords = NULL; /* optimization shortcut * obj["literal"] = value -> opt_aset_with(obj, "literal", value) @@ -9694,7 +9695,7 @@ compile_attrasgn(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node INIT_ANCHOR(recv); INIT_ANCHOR(args); - argc = setup_args(iseq, args, RNODE_ATTRASGN(node)->nd_args, &flag, NULL); + argc = setup_args(iseq, args, RNODE_ATTRASGN(node)->nd_args, &flag, &keywords); CHECK(!NIL_P(argc)); int asgnflag = COMPILE_RECV(recv, "recv", node, RNODE_ATTRASGN(node)->nd_recv); diff --git a/version.h b/version.h index 1623f73fdf6ec3..5a6e060a2e2560 100644 --- a/version.h +++ b/version.h @@ -11,7 +11,7 @@ # define RUBY_VERSION_MINOR RUBY_API_VERSION_MINOR #define RUBY_VERSION_TEENY 7 #define RUBY_RELEASE_DATE RUBY_RELEASE_YEAR_STR"-"RUBY_RELEASE_MONTH_STR"-"RUBY_RELEASE_DAY_STR -#define RUBY_PATCHLEVEL 128 +#define RUBY_PATCHLEVEL 129 #include "ruby/version.h" #include "ruby/internal/abi.h" From da86a9959b4c5bbdefb6fd1000a0251a151ffbc1 Mon Sep 17 00:00:00 2001 From: nagachika Date: Sun, 16 Mar 2025 15:25:20 +0900 Subject: [PATCH 19/41] merge revision(s) 2b6fc9ea7212543a1be26768403f59c7a759b5ea: [Backport #21092] [Bug #21092] Fallback variables after execonf has done When reading from a dummy makefile, the global variables initialized in `init_mkmf` may not be overridden. --- ext/extmk.rb | 6 +++--- version.h | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/ext/extmk.rb b/ext/extmk.rb index d9c2417dfa2556..da0b06aaa5f7e8 100755 --- a/ext/extmk.rb +++ b/ext/extmk.rb @@ -167,8 +167,6 @@ def extmake(target, basedir = 'ext', maybestatic = true) $mdir = target $srcdir = File.join($top_srcdir, basedir, $mdir) $preload = nil - $objs = [] - $srcs = [] $extso = [] makefile = "./Makefile" static = $static @@ -202,7 +200,7 @@ def extmake(target, basedir = 'ext', maybestatic = true) begin $extconf_h = nil ok &&= extract_makefile(makefile) - old_objs = $objs + old_objs = $objs || [] old_cleanfiles = $distcleanfiles | $cleanfiles conf = ["#{$srcdir}/makefile.rb", "#{$srcdir}/extconf.rb"].find {|f| File.exist?(f)} if (!ok || ($extconf_h && !File.exist?($extconf_h)) || @@ -265,6 +263,8 @@ def extmake(target, basedir = 'ext', maybestatic = true) unless $destdir.to_s.empty? or $mflags.defined?("DESTDIR") args += ["DESTDIR=" + relative_from($destdir, "../"+prefix)] end + $objs ||= [] + $srcs ||= [] if $static and ok and !$objs.empty? and !noinstall args += ["static"] $extlist.push [(maybestatic ? $static : false), target, $target, $preload] diff --git a/version.h b/version.h index 5a6e060a2e2560..08ec2cced804c8 100644 --- a/version.h +++ b/version.h @@ -11,7 +11,7 @@ # define RUBY_VERSION_MINOR RUBY_API_VERSION_MINOR #define RUBY_VERSION_TEENY 7 #define RUBY_RELEASE_DATE RUBY_RELEASE_YEAR_STR"-"RUBY_RELEASE_MONTH_STR"-"RUBY_RELEASE_DAY_STR -#define RUBY_PATCHLEVEL 129 +#define RUBY_PATCHLEVEL 130 #include "ruby/version.h" #include "ruby/internal/abi.h" From 1d3c19871d7a0d05a0f0a80e78cfad843b7ef324 Mon Sep 17 00:00:00 2001 From: nagachika Date: Sun, 16 Mar 2025 15:39:32 +0900 Subject: [PATCH 20/41] merge revision(s) 931ac960b6d11937364b6c4e847fdd575ee67980: [Backport #21159] [Bug #21159] module names should not be modifiable --- test/ruby/test_module.rb | 38 ++++++++++++++++++++++++++++++++++++++ variable.c | 2 ++ version.h | 2 +- 3 files changed, 41 insertions(+), 1 deletion(-) diff --git a/test/ruby/test_module.rb b/test/ruby/test_module.rb index 29b71bc027e700..f2accd0c594d2a 100644 --- a/test/ruby/test_module.rb +++ b/test/ruby/test_module.rb @@ -3353,6 +3353,44 @@ def test_module_clone_memory_leak CODE end + def test_set_temporary_name + m = Module.new + assert_nil m.name + + m.const_set(:N, Module.new) + + assert_match(/\A#::N\z/, m::N.name) + m::N.set_temporary_name(name = "fake_name_under_M") + name.upcase! + assert_equal("fake_name_under_M", m::N.name) + assert_raise(FrozenError) {m::N.name.upcase!} + m::N.set_temporary_name(nil) + assert_nil(m::N.name) + + m.set_temporary_name(name = "fake_name") + name.upcase! + assert_equal("fake_name", m.name) + assert_raise(FrozenError) {m.name.upcase!} + + m.set_temporary_name(nil) + assert_nil m.name + + assert_raise_with_message(ArgumentError, "empty class/module name") do + m.set_temporary_name("") + end + %w[A A::B ::A ::A::B].each do |name| + assert_raise_with_message(ArgumentError, /must not be a constant path/) do + m.set_temporary_name(name) + end + end + + [Object, User, AClass].each do |mod| + assert_raise_with_message(RuntimeError, /permanent name/) do + mod.set_temporary_name("fake_name") + end + end + end + private def assert_top_method_is_private(method) diff --git a/variable.c b/variable.c index 1a4f919c4c77e1..ea73dd00dc23f0 100644 --- a/variable.c +++ b/variable.c @@ -228,6 +228,8 @@ rb_mod_set_temporary_name(VALUE mod, VALUE name) rb_raise(rb_eArgError, "the temporary name must not be a constant path to avoid confusion"); } + name = rb_str_new_frozen(name); + // Set the temporary classpath to the given name: RCLASS_SET_CLASSPATH(mod, name, FALSE); } diff --git a/version.h b/version.h index 08ec2cced804c8..ecddbf549c9c21 100644 --- a/version.h +++ b/version.h @@ -11,7 +11,7 @@ # define RUBY_VERSION_MINOR RUBY_API_VERSION_MINOR #define RUBY_VERSION_TEENY 7 #define RUBY_RELEASE_DATE RUBY_RELEASE_YEAR_STR"-"RUBY_RELEASE_MONTH_STR"-"RUBY_RELEASE_DAY_STR -#define RUBY_PATCHLEVEL 130 +#define RUBY_PATCHLEVEL 131 #include "ruby/version.h" #include "ruby/internal/abi.h" From 726bff43b462d2a1b0bc93299cf031202f7fe7a1 Mon Sep 17 00:00:00 2001 From: nagachika Date: Sun, 16 Mar 2025 18:02:45 +0900 Subject: [PATCH 21/41] merge revision(s) c224ca4feaff20cab03d76439bcbfb35d4e2f6b1: [Backport #21172] Fix a race condition with interned strings sweeping. [Bug #21172] This fixes a rare CI failure. The timeline of the race condition is: - A `"foo" oid=1` string is interned. - `"foo" oid=1` is no longer referenced and will be swept in the future. - Another `"foo" oid=2` string is interned. - `register_fstring` finds `"foo" oid=1`, but since it is about to be swept, removes it from `fstring_table` and insert `"foo" oid=2` instead. - `"foo" oid=1` is swept, since it has the `RSTRING_FSTR` flag, a `st_delete` is issued in `fstring_table` which removes `"foo" oid=2`. I don't know how to reproduce this bug consistently in a single test case. --- string.c | 4 ++++ version.h | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/string.c b/string.c index a28d682a841a60..7c3a790fa3b78d 100644 --- a/string.c +++ b/string.c @@ -344,6 +344,10 @@ fstr_update_callback(st_data_t *key, st_data_t *value, st_data_t data, int exist if (rb_objspace_garbage_object_p(str)) { arg->fstr = Qundef; + // When RSTRING_FSTR strings are swept, they call `st_delete`. + // To avoid a race condition if an equivalent string was inserted + // we must remove the flag immediately. + FL_UNSET_RAW(str, RSTRING_FSTR); return ST_DELETE; } diff --git a/version.h b/version.h index ecddbf549c9c21..cc73220a9869e4 100644 --- a/version.h +++ b/version.h @@ -11,7 +11,7 @@ # define RUBY_VERSION_MINOR RUBY_API_VERSION_MINOR #define RUBY_VERSION_TEENY 7 #define RUBY_RELEASE_DATE RUBY_RELEASE_YEAR_STR"-"RUBY_RELEASE_MONTH_STR"-"RUBY_RELEASE_DAY_STR -#define RUBY_PATCHLEVEL 131 +#define RUBY_PATCHLEVEL 132 #include "ruby/version.h" #include "ruby/internal/abi.h" From d213eb7f453fa0bd6c476826c450d9726c3c8b15 Mon Sep 17 00:00:00 2001 From: nagachika Date: Sun, 16 Mar 2025 18:46:04 +0900 Subject: [PATCH 22/41] merge revision(s) 3f07bc76ff6a11232d9f18e5eaa31835c195e8f0, 34098b669c0cbc024cd08e686891f1dfe0a10aaf: [Backport #21144] [Bug #21144] Win32: Use Windows time zone ID if TZ is not set If the TZ environment variable is not set, the time zone names retrieved from the system are localized for UI display and may vary across editions and language packs for the same time zone. Use the time zone IDs that are invariant across environments instead. [Bug #21144] Win32: Convert the time zone name to the current locale The Windows time zone IDs provided by Microsoft as of 24H1 are ASCII only all, but the API itself is not impossible to set non-ASCII key name. Prefer the current locale encoding for now until we move to UTF-8 including environment variables and command line arguments. --- hash.c | 8 +++---- internal/time.h | 5 +++- time.c | 63 +++++++++++++++++++++++++++++++++++++++++++++---- version.h | 2 +- 4 files changed, 67 insertions(+), 11 deletions(-) diff --git a/hash.c b/hash.c index 79e869b13f7d4a..6b1941ebcbee8e 100644 --- a/hash.c +++ b/hash.c @@ -4905,7 +4905,7 @@ env_name(volatile VALUE *s) static VALUE env_aset(VALUE nm, VALUE val); static void -reset_by_modified_env(const char *nam) +reset_by_modified_env(const char *nam, const char *val) { /* * ENV['TZ'] = nil has a special meaning. @@ -4914,7 +4914,7 @@ reset_by_modified_env(const char *nam) * This hack might works only on Linux glibc. */ if (ENVMATCH(nam, TZ_ENV)) { - ruby_reset_timezone(); + ruby_reset_timezone(val); } } @@ -4922,7 +4922,7 @@ static VALUE env_delete(VALUE name) { const char *nam = env_name(name); - reset_by_modified_env(nam); + reset_by_modified_env(nam, NULL); VALUE val = getenv_with_lock(nam); if (!NIL_P(val)) { @@ -5380,7 +5380,7 @@ env_aset(VALUE nm, VALUE val) get_env_ptr(value, val); ruby_setenv(name, value); - reset_by_modified_env(name); + reset_by_modified_env(name, value); return val; } diff --git a/internal/time.h b/internal/time.h index a3bf0587ecfd14..e21b3574f6db7a 100644 --- a/internal/time.h +++ b/internal/time.h @@ -28,7 +28,10 @@ struct timeval rb_time_timeval(VALUE); RUBY_SYMBOL_EXPORT_BEGIN /* time.c (export) */ void ruby_reset_leap_second_info(void); -void ruby_reset_timezone(void); +#ifdef RBIMPL_ATTR_DEPRECATED_INTERNAL_ONLY +RBIMPL_ATTR_DEPRECATED_INTERNAL_ONLY() +#endif +void ruby_reset_timezone(const char *); RUBY_SYMBOL_EXPORT_END #endif /* INTERNAL_TIME_H */ diff --git a/time.c b/time.c index 25098e7e769e72..082ddd43b6885c 100644 --- a/time.c +++ b/time.c @@ -44,6 +44,10 @@ #include "ruby/encoding.h" #include "timev.h" +#if defined(_WIN32) +# include "timezoneapi.h" /* DYNAMIC_TIME_ZONE_INFORMATION */ +#endif + #include "builtin.h" static ID id_submicro, id_nano_num, id_nano_den, id_offset, id_zone; @@ -697,10 +701,51 @@ static VALUE tm_from_time(VALUE klass, VALUE time); bool ruby_tz_uptodate_p; +#ifdef _WIN32 +enum {tzkey_max = numberof(((DYNAMIC_TIME_ZONE_INFORMATION *)NULL)->TimeZoneKeyName)}; +static struct { + char use_tzkey; + char name[tzkey_max * 4 + 1]; +} w32_tz; + +static char * +get_tzname(int dst) +{ + if (w32_tz.use_tzkey) { + if (w32_tz.name[0]) { + return w32_tz.name; + } + else { + /* + * Use GetDynamicTimeZoneInformation::TimeZoneKeyName, Windows + * time zone ID, which is not localized because it is the key + * for "Dynamic DST" keys under the "Time Zones" registry. + * Available since Windows Vista and Windows Server 2008. + */ + DYNAMIC_TIME_ZONE_INFORMATION tzi; + WCHAR *const wtzkey = tzi.TimeZoneKeyName; + DWORD tzret = GetDynamicTimeZoneInformation(&tzi); + if (tzret != TIME_ZONE_ID_INVALID && *wtzkey) { + int wlen = (int)wcsnlen(wtzkey, tzkey_max); + int clen = WideCharToMultiByte(CP_UTF8, 0, wtzkey, wlen, + w32_tz.name, sizeof(w32_tz.name) - 1, + NULL, NULL); + w32_tz.name[clen] = '\0'; + return w32_tz.name; + } + } + } + return _tzname[_daylight && dst]; +} +#endif + void -ruby_reset_timezone(void) +ruby_reset_timezone(const char *val) { ruby_tz_uptodate_p = false; +#ifdef _WIN32 + w32_tz.use_tzkey = !val || !*val; +#endif ruby_reset_leap_second_info(); } @@ -946,7 +991,13 @@ zone_str(const char *zone) str = rb_usascii_str_new(zone, len); } else { +#ifdef _WIN32 + str = rb_utf8_str_new(zone, len); + /* until we move to UTF-8 on Windows completely */ + str = rb_str_export_locale(str); +#else str = rb_enc_str_new(zone, len, rb_locale_encoding()); +#endif } return rb_fstring(str); } @@ -1645,11 +1696,9 @@ localtime_with_gmtoff_zone(const time_t *t, struct tm *result, long *gmtoff, VAL if (zone) { #if defined(HAVE_TM_ZONE) *zone = zone_str(tm.tm_zone); +#elif defined(_WIN32) + *zone = zone_str(get_tzname(tm.tm_isdst)); #elif defined(HAVE_TZNAME) && defined(HAVE_DAYLIGHT) -# if defined(RUBY_MSVCRT_VERSION) && RUBY_MSVCRT_VERSION >= 140 -# define tzname _tzname -# define daylight _daylight -# endif /* this needs tzset or localtime, instead of localtime_r */ *zone = zone_str(tzname[daylight && tm.tm_isdst]); #else @@ -5727,6 +5776,10 @@ rb_time_zone_abbreviation(VALUE zone, VALUE time) void Init_Time(void) { +#ifdef _WIN32 + ruby_reset_timezone(getenv("TZ")); +#endif + id_submicro = rb_intern_const("submicro"); id_nano_num = rb_intern_const("nano_num"); id_nano_den = rb_intern_const("nano_den"); diff --git a/version.h b/version.h index cc73220a9869e4..a83aa1824dc35f 100644 --- a/version.h +++ b/version.h @@ -11,7 +11,7 @@ # define RUBY_VERSION_MINOR RUBY_API_VERSION_MINOR #define RUBY_VERSION_TEENY 7 #define RUBY_RELEASE_DATE RUBY_RELEASE_YEAR_STR"-"RUBY_RELEASE_MONTH_STR"-"RUBY_RELEASE_DAY_STR -#define RUBY_PATCHLEVEL 132 +#define RUBY_PATCHLEVEL 133 #include "ruby/version.h" #include "ruby/internal/abi.h" From 2b2ab1a67c236eb0c47e63e8adcf877b0d20a38c Mon Sep 17 00:00:00 2001 From: nagachika Date: Sun, 16 Mar 2025 18:52:56 +0900 Subject: [PATCH 23/41] merge revision(s) 08b3a45bc97c835b4677bf76dbce68fd51d81897: [Backport #21180] Push a real iseq in rb_vm_push_frame_fname() Previously, vm_make_env_each() (used during proc creation and for the debug inspector C API) picked up the non-GC-allocated iseq that rb_vm_push_frame_fname() creates, which led to a SEGV when the GC tried to mark the non GC object. Put a real iseq imemo instead. Speed should be about the same since the old code also did a imemo allocation and a malloc allocation. Real iseq allows ironing out the special-casing of dummy frames in rb_execution_context_mark() and rb_execution_context_update(). A check is added to RubyVM::ISeq#eval, though, to stop attempts to run dummy iseqs. [Bug #21180] Co-authored-by: Aaron Patterson --- iseq.c | 19 ++++++++++++++++++- test/fiber/test_scheduler.rb | 13 +++++++++++++ version.h | 2 +- vm.c | 26 ++++++++++++-------------- vm_insnhelper.c | 13 +++---------- 5 files changed, 47 insertions(+), 26 deletions(-) diff --git a/iseq.c b/iseq.c index 672bbccd987bb8..3bdb1c0af50e05 100644 --- a/iseq.c +++ b/iseq.c @@ -533,6 +533,19 @@ rb_iseq_pathobj_set(const rb_iseq_t *iseq, VALUE path, VALUE realpath) rb_iseq_pathobj_new(path, realpath)); } +// Make a dummy iseq for a dummy frame that exposes a path for profilers to inspect +rb_iseq_t * +rb_iseq_alloc_with_dummy_path(VALUE fname) +{ + rb_iseq_t *dummy_iseq = iseq_alloc(); + + ISEQ_BODY(dummy_iseq)->type = ISEQ_TYPE_TOP; + RB_OBJ_WRITE(dummy_iseq, &ISEQ_BODY(dummy_iseq)->location.pathobj, fname); + RB_OBJ_WRITE(dummy_iseq, &ISEQ_BODY(dummy_iseq)->location.label, fname); + + return dummy_iseq; +} + static rb_iseq_location_t * iseq_location_setup(rb_iseq_t *iseq, VALUE name, VALUE path, VALUE realpath, int first_lineno, const rb_code_location_t *code_location, const int node_id) { @@ -1672,7 +1685,11 @@ rb_iseqw_to_iseq(VALUE iseqw) static VALUE iseqw_eval(VALUE self) { - return rb_iseq_eval(iseqw_check(self)); + const rb_iseq_t *iseq = iseqw_check(self); + if (0 == ISEQ_BODY(iseq)->iseq_size) { + rb_raise(rb_eTypeError, "attempt to evaluate dummy InstructionSequence"); + } + return rb_iseq_eval(iseq); } /* diff --git a/test/fiber/test_scheduler.rb b/test/fiber/test_scheduler.rb index 62424fc48939f6..81d4581bea7950 100644 --- a/test/fiber/test_scheduler.rb +++ b/test/fiber/test_scheduler.rb @@ -139,6 +139,19 @@ def test_autoload end end + def test_iseq_compile_under_gc_stress_bug_21180 + Thread.new do + scheduler = Scheduler.new + Fiber.set_scheduler scheduler + + Fiber.schedule do + EnvUtil.under_gc_stress do + RubyVM::InstructionSequence.compile_file(File::NULL) + end + end + end.join + end + def test_deadlock mutex = Thread::Mutex.new condition = Thread::ConditionVariable.new diff --git a/version.h b/version.h index a83aa1824dc35f..4b21ab9908666b 100644 --- a/version.h +++ b/version.h @@ -11,7 +11,7 @@ # define RUBY_VERSION_MINOR RUBY_API_VERSION_MINOR #define RUBY_VERSION_TEENY 7 #define RUBY_RELEASE_DATE RUBY_RELEASE_YEAR_STR"-"RUBY_RELEASE_MONTH_STR"-"RUBY_RELEASE_DAY_STR -#define RUBY_PATCHLEVEL 133 +#define RUBY_PATCHLEVEL 134 #include "ruby/version.h" #include "ruby/internal/abi.h" diff --git a/vm.c b/vm.c index 62ea5be53b6f27..9fb7cb017f05e1 100644 --- a/vm.c +++ b/vm.c @@ -3327,21 +3327,19 @@ rb_execution_context_mark(const rb_execution_context_t *ec) const VALUE *ep = cfp->ep; VM_ASSERT(!!VM_ENV_FLAGS(ep, VM_ENV_FLAG_ESCAPED) == vm_ep_in_heap_p_(ec, ep)); - if (VM_FRAME_TYPE(cfp) != VM_FRAME_MAGIC_DUMMY) { - rb_gc_mark_movable(cfp->self); - rb_gc_mark_movable((VALUE)cfp->iseq); - rb_gc_mark_movable((VALUE)cfp->block_code); - - if (!VM_ENV_LOCAL_P(ep)) { - const VALUE *prev_ep = VM_ENV_PREV_EP(ep); - if (VM_ENV_FLAGS(prev_ep, VM_ENV_FLAG_ESCAPED)) { - rb_gc_mark_movable(prev_ep[VM_ENV_DATA_INDEX_ENV]); - } + rb_gc_mark_movable(cfp->self); + rb_gc_mark_movable((VALUE)cfp->iseq); + rb_gc_mark_movable((VALUE)cfp->block_code); - if (VM_ENV_FLAGS(ep, VM_ENV_FLAG_ESCAPED)) { - rb_gc_mark_movable(ep[VM_ENV_DATA_INDEX_ENV]); - rb_gc_mark(ep[VM_ENV_DATA_INDEX_ME_CREF]); - } + if (!VM_ENV_LOCAL_P(ep)) { + const VALUE *prev_ep = VM_ENV_PREV_EP(ep); + if (VM_ENV_FLAGS(prev_ep, VM_ENV_FLAG_ESCAPED)) { + rb_gc_mark_movable(prev_ep[VM_ENV_DATA_INDEX_ENV]); + } + + if (VM_ENV_FLAGS(ep, VM_ENV_FLAG_ESCAPED)) { + rb_gc_mark_movable(ep[VM_ENV_DATA_INDEX_ENV]); + rb_gc_mark(ep[VM_ENV_DATA_INDEX_ME_CREF]); } } diff --git a/vm_insnhelper.c b/vm_insnhelper.c index 7284769854fcbf..1af20721a73351 100644 --- a/vm_insnhelper.c +++ b/vm_insnhelper.c @@ -444,15 +444,8 @@ rb_vm_pop_frame(rb_execution_context_t *ec) VALUE rb_vm_push_frame_fname(rb_execution_context_t *ec, VALUE fname) { - VALUE tmpbuf = rb_imemo_tmpbuf_auto_free_pointer(); - void *ptr = ruby_xcalloc(sizeof(struct rb_iseq_constant_body) + sizeof(struct rb_iseq_struct), 1); - rb_imemo_tmpbuf_set_ptr(tmpbuf, ptr); - - struct rb_iseq_struct *dmy_iseq = (struct rb_iseq_struct *)ptr; - struct rb_iseq_constant_body *dmy_body = (struct rb_iseq_constant_body *)&dmy_iseq[1]; - dmy_iseq->body = dmy_body; - dmy_body->type = ISEQ_TYPE_TOP; - dmy_body->location.pathobj = fname; + rb_iseq_t *rb_iseq_alloc_with_dummy_path(VALUE fname); + rb_iseq_t *dmy_iseq = rb_iseq_alloc_with_dummy_path(fname); vm_push_frame(ec, dmy_iseq, //const rb_iseq_t *iseq, @@ -465,7 +458,7 @@ rb_vm_push_frame_fname(rb_execution_context_t *ec, VALUE fname) 0, // int local_size, 0); // int stack_max - return tmpbuf; + return (VALUE)dmy_iseq; } /* method dispatch */ From f85e5e01bafeca387e833b9d79cab43a8b22aa3d Mon Sep 17 00:00:00 2001 From: nagachika Date: Sun, 16 Mar 2025 20:10:00 +0900 Subject: [PATCH 24/41] merge revision(s) f423f6e10c0c226dfed98e7cb7a5d489191dfa35: [Backport #21131] Ensure IO.copy_stream buffer is an independent string Otherwise, changes to the buffer by the destination write method could result in data changing for supposedly independent strings. Fixes [Bug #21131] --- io.c | 1 + test/ruby/test_io.rb | 28 ++++++++++++++++++++++++++++ version.h | 2 +- 3 files changed, 30 insertions(+), 1 deletion(-) diff --git a/io.c b/io.c index 17f8d5799a68b3..7f23656049501a 100644 --- a/io.c +++ b/io.c @@ -13098,6 +13098,7 @@ copy_stream_fallback_body(VALUE arg) while (1) { long numwrote; long l; + rb_str_make_independent(buf); if (stp->copy_length < (rb_off_t)0) { l = buflen; } diff --git a/test/ruby/test_io.rb b/test/ruby/test_io.rb index 51c9f2b83c5018..16de2e8a76a955 100644 --- a/test/ruby/test_io.rb +++ b/test/ruby/test_io.rb @@ -1116,6 +1116,34 @@ def test_copy_stream_pathname_to_pathname } end + def test_copy_stream_dup_buffer + bug21131 = '[ruby-core:120961] [Bug #21131]' + mkcdtmpdir do + dst_class = Class.new do + def initialize(&block) + @block = block + end + + def write(data) + @block.call(data.dup) + data.bytesize + end + end + + rng = Random.new(42) + body = Tempfile.new("ruby-bug", binmode: true) + body.write(rng.bytes(16_385)) + body.rewind + + payload = [] + IO.copy_stream(body, dst_class.new{|cls| payload << cls}) + body.rewind + assert_equal(body.read, payload.join, bug21131) + ensure + body&.close + end + end + def test_copy_stream_write_in_binmode bug8767 = '[ruby-core:56518] [Bug #8767]' mkcdtmpdir { diff --git a/version.h b/version.h index 4b21ab9908666b..63f382a26da948 100644 --- a/version.h +++ b/version.h @@ -11,7 +11,7 @@ # define RUBY_VERSION_MINOR RUBY_API_VERSION_MINOR #define RUBY_VERSION_TEENY 7 #define RUBY_RELEASE_DATE RUBY_RELEASE_YEAR_STR"-"RUBY_RELEASE_MONTH_STR"-"RUBY_RELEASE_DAY_STR -#define RUBY_PATCHLEVEL 134 +#define RUBY_PATCHLEVEL 135 #include "ruby/version.h" #include "ruby/internal/abi.h" From c1319d7e406ddf3f0da487296f1c4c50d90496ad Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20Rodr=C3=ADguez?= Date: Thu, 20 Mar 2025 18:19:58 +0100 Subject: [PATCH 25/41] [rubygems/rubygems] Support git 2.49 One error message that we parse is now slightly different. https://github.com/rubygems/rubygems/commit/758528791d --- lib/bundler/source/git/git_proxy.rb | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/lib/bundler/source/git/git_proxy.rb b/lib/bundler/source/git/git_proxy.rb index 744235bc046d7e..86c45780aefcea 100644 --- a/lib/bundler/source/git/git_proxy.rb +++ b/lib/bundler/source/git/git_proxy.rb @@ -185,7 +185,8 @@ def clone_needs_extra_fetch? _, err, status = capture(command, nil) return extra_ref if status.success? - if err.include?("Could not find remote branch") + if err.include?("Could not find remote branch") || # git up to 2.49 + err.include?("Remote branch #{branch_option} not found") # git 2.49 or higher raise MissingGitRevisionError.new(command_with_no_credentials, nil, explicit_ref, credential_filtered_uri) else idx = command.index("--depth") @@ -262,7 +263,7 @@ def fully_qualified_ref end def not_pinned? - branch || tag || ref.nil? + branch_option || ref.nil? end def pinned_to_full_sha? @@ -426,7 +427,7 @@ def extra_clone_args # anyways. return args if @revision - args += ["--branch", branch || tag] if branch || tag + args += ["--branch", branch_option] if branch_option args end @@ -442,6 +443,10 @@ def extra_fetch_args(ref) extra_args end + def branch_option + branch || tag + end + def full_clone? depth.nil? end From d2eda78e4091a99c1a387d43967af5794d8eac70 Mon Sep 17 00:00:00 2001 From: nagachika Date: Sat, 29 Mar 2025 15:21:40 +0900 Subject: [PATCH 26/41] merge revision(s) 9459bedd84d479bb1d7d3d40bada1cecb4701c37: [Backport #19841] [Bug #19841] Refine error on marshaling recursive USERDEF --- marshal.c | 17 +++++++++++++++++ test/ruby/test_marshal.rb | 9 +++++++++ version.h | 2 +- 3 files changed, 27 insertions(+), 1 deletion(-) diff --git a/marshal.c b/marshal.c index 1cd71efd54fe31..6cb636f3ff78b3 100644 --- a/marshal.c +++ b/marshal.c @@ -173,6 +173,7 @@ struct dump_arg { st_table *data; st_table *compat_tbl; st_table *encodings; + st_table *userdefs; st_index_t num_entries; }; @@ -221,6 +222,7 @@ mark_dump_arg(void *ptr) rb_mark_set(p->symbols); rb_mark_set(p->data); rb_mark_hash(p->compat_tbl); + rb_mark_set(p->userdefs); rb_gc_mark(p->str); } @@ -238,6 +240,7 @@ memsize_dump_arg(const void *ptr) if (p->symbols) memsize += rb_st_memsize(p->symbols); if (p->data) memsize += rb_st_memsize(p->data); if (p->compat_tbl) memsize += rb_st_memsize(p->compat_tbl); + if (p->userdefs) memsize += rb_st_memsize(p->userdefs); if (p->encodings) memsize += rb_st_memsize(p->encodings); return memsize; } @@ -904,6 +907,9 @@ w_object(VALUE obj, struct dump_arg *arg, int limit) st_index_t hasiv2; VALUE encname2; + if (arg->userdefs && st_is_member(arg->userdefs, (st_data_t)obj)) { + rb_raise(rb_eRuntimeError, "can't dump recursive object using _dump()"); + } v = INT2NUM(limit); v = dump_funcall(arg, obj, s_dump, 1, &v); if (!RB_TYPE_P(v, T_STRING)) { @@ -920,7 +926,13 @@ w_object(VALUE obj, struct dump_arg *arg, int limit) w_class(TYPE_USERDEF, obj, arg, FALSE); w_bytes(RSTRING_PTR(v), RSTRING_LEN(v), arg); if (hasiv) { + st_data_t userdefs = (st_data_t)obj; + if (!arg->userdefs) { + arg->userdefs = rb_init_identtable(); + } + st_add_direct(arg->userdefs, userdefs, 0); w_ivar(hasiv, ivobj, encname, &c_arg); + st_delete(arg->userdefs, &userdefs, NULL); } w_remember(obj, arg); return; @@ -1127,6 +1139,10 @@ clear_dump_arg(struct dump_arg *arg) st_free_table(arg->encodings); arg->encodings = 0; } + if (arg->userdefs) { + st_free_table(arg->userdefs); + arg->userdefs = 0; + } } NORETURN(static inline void io_needed(void)); @@ -1204,6 +1220,7 @@ rb_marshal_dump_limited(VALUE obj, VALUE port, int limit) arg->num_entries = 0; arg->compat_tbl = 0; arg->encodings = 0; + arg->userdefs = 0; arg->str = rb_str_buf_new(0); if (!NIL_P(port)) { if (!rb_respond_to(port, s_write)) { diff --git a/test/ruby/test_marshal.rb b/test/ruby/test_marshal.rb index 13645e3aa805f8..c27de3524e189e 100644 --- a/test/ruby/test_marshal.rb +++ b/test/ruby/test_marshal.rb @@ -668,6 +668,15 @@ class << c end end + def test_recursive_userdef + t = Time.utc(0) + str = "b".b + t.instance_eval {@v = t} + assert_raise_with_message(RuntimeError, /recursive\b.*\b_dump/) do + Marshal.dump(t) + end + end + def test_unloadable_usrmarshal c = eval("class UsrMarshal\u{23F0 23F3} Date: Sat, 29 Mar 2025 15:25:02 +0900 Subject: [PATCH 27/41] merge revision(s) 1acfb29015dbc38fd345d8786aa78aad59f7dcd1: [Backport #21186] [Bug #21186] multibyte char literal should be a single letter word --- parse.y | 13 ++++++------- test/ruby/test_parse.rb | 2 ++ version.h | 2 +- 3 files changed, 9 insertions(+), 8 deletions(-) diff --git a/parse.y b/parse.y index baf391e52d2d2c..f84320b4b445e4 100644 --- a/parse.y +++ b/parse.y @@ -9884,6 +9884,7 @@ parse_qmark(struct parser_params *p, int space_seen) rb_encoding *enc; register int c; VALUE lit; + const char *start = p->lex.pcur; if (IS_END()) { SET_LEX_STATE(EXPR_VALUE); @@ -9908,13 +9909,11 @@ parse_qmark(struct parser_params *p, int space_seen) } newtok(p); enc = p->enc; - if (!parser_isascii(p)) { - if (tokadd_mbchar(p, c) == -1) return 0; - } - else if ((rb_enc_isalnum(c, p->enc) || c == '_') && - !lex_eol_p(p) && is_identchar(p, p->lex.pcur, p->lex.pend, p->enc)) { + int w = parser_precise_mbclen(p, start); + if (is_identchar(p, start, p->lex.pend, p->enc) && + !(lex_eol_ptr_n_p(p, start, w) || !is_identchar(p, start + w, p->lex.pend, p->enc))) { if (space_seen) { - const char *start = p->lex.pcur - 1, *ptr = start; + const char *ptr = start; do { int n = parser_precise_mbclen(p, ptr); if (n < 0) return -1; @@ -9942,7 +9941,7 @@ parse_qmark(struct parser_params *p, int space_seen) } } else { - tokadd(p, c); + if (tokadd_mbchar(p, c) == -1) return 0; } tokfix(p); lit = STR_NEW3(tok(p), toklen(p), enc, 0); diff --git a/test/ruby/test_parse.rb b/test/ruby/test_parse.rb index 341d63c38a7185..28cd5bf1f0b9eb 100644 --- a/test/ruby/test_parse.rb +++ b/test/ruby/test_parse.rb @@ -631,6 +631,8 @@ def test_question assert_equal("\u{1234}", eval('?\u{1234}')) assert_equal("\u{1234}", eval('?\u1234')) assert_syntax_error('?\u{41 42}', 'Multiple codepoints at single character literal') + assert_syntax_error("?and", /unexpected '\?'/) + assert_syntax_error("?\u1234and", /unexpected '\?'/) e = assert_syntax_error('"#{?\u123}"', 'invalid Unicode escape') assert_not_match(/end-of-input/, e.message) diff --git a/version.h b/version.h index 4a81276a08b408..7d9016b4498852 100644 --- a/version.h +++ b/version.h @@ -11,7 +11,7 @@ # define RUBY_VERSION_MINOR RUBY_API_VERSION_MINOR #define RUBY_VERSION_TEENY 7 #define RUBY_RELEASE_DATE RUBY_RELEASE_YEAR_STR"-"RUBY_RELEASE_MONTH_STR"-"RUBY_RELEASE_DAY_STR -#define RUBY_PATCHLEVEL 136 +#define RUBY_PATCHLEVEL 137 #include "ruby/version.h" #include "ruby/internal/abi.h" From aac5c546cd35ff0aeab120e3724fbb1296892ae3 Mon Sep 17 00:00:00 2001 From: nagachika Date: Sat, 29 Mar 2025 16:49:59 +0900 Subject: [PATCH 28/41] merge revision(s) f69ad0e810e1fdc18dc12f77bbecfa49999ef3bf: [Backport #21094] [Bug #21094] Update nested module names when setting temporary name --- .../core/module/set_temporary_name_spec.rb | 45 ++++++++++ test/ruby/test_module.rb | 9 ++ variable.c | 85 ++++++++++++++++++- version.h | 2 +- 4 files changed, 137 insertions(+), 4 deletions(-) diff --git a/spec/ruby/core/module/set_temporary_name_spec.rb b/spec/ruby/core/module/set_temporary_name_spec.rb index f5886a33988ee1..9a4d027aad200e 100644 --- a/spec/ruby/core/module/set_temporary_name_spec.rb +++ b/spec/ruby/core/module/set_temporary_name_spec.rb @@ -64,5 +64,50 @@ module m::N; end m::M = m::N m::M.name.should =~ /\A#::M\z/m end + + it "can reassign a temporary name repeatedly" do + m = Module.new + + m.set_temporary_name("fake_name") + m.name.should == "fake_name" + + m.set_temporary_name("fake_name_2") + m.name.should == "fake_name_2" + end + + ruby_bug "#21094", ""..."3.5" do + it "also updates a name of a nested module" do + m = Module.new + m::N = Module.new + m::N.name.should =~ /\A#::N\z/ + + m.set_temporary_name "m" + m::N.name.should == "m::N" + + m.set_temporary_name nil + m::N.name.should == nil + end + end + + it "keeps temporary name when assigned in an anonymous module" do + outer = Module.new + m = Module.new + m.set_temporary_name "m" + m.name.should == "m" + outer::M = m + m.name.should == "m" + m.inspect.should == "m" + end + + it "keeps temporary name when assigned in an anonymous module and nested before" do + outer = Module.new + m = Module.new + outer::A = m + m.set_temporary_name "m" + m.name.should == "m" + outer::M = m + m.name.should == "m" + m.inspect.should == "m" + end end end diff --git a/test/ruby/test_module.rb b/test/ruby/test_module.rb index f2accd0c594d2a..7de50c4c794d9c 100644 --- a/test/ruby/test_module.rb +++ b/test/ruby/test_module.rb @@ -3367,13 +3367,22 @@ def test_set_temporary_name m::N.set_temporary_name(nil) assert_nil(m::N.name) + m::N.const_set(:O, Module.new) + m.const_set(:Recursive, m) + m::N.const_set(:Recursive, m) + m.const_set(:A, 42) + m.set_temporary_name(name = "fake_name") name.upcase! assert_equal("fake_name", m.name) assert_raise(FrozenError) {m.name.upcase!} + assert_equal("fake_name::N", m::N.name) + assert_equal("fake_name::N::O", m::N::O.name) m.set_temporary_name(nil) assert_nil m.name + assert_nil m::N.name + assert_nil m::N::O.name assert_raise_with_message(ArgumentError, "empty class/module name") do m.set_temporary_name("") diff --git a/variable.c b/variable.c index ea73dd00dc23f0..f8cf7d735e9222 100644 --- a/variable.c +++ b/variable.c @@ -157,6 +157,80 @@ is_constant_path(VALUE name) return true; } +struct sub_temporary_name_args { + VALUE names; + ID last; +}; + +static VALUE build_const_path(VALUE head, ID tail); +static void set_sub_temporary_name_foreach(VALUE mod, struct sub_temporary_name_args *args, VALUE name); + +static VALUE +set_sub_temporary_name_recursive(VALUE mod, VALUE data, int recursive) +{ + if (recursive) return Qfalse; + + struct sub_temporary_name_args *args = (void *)data; + VALUE name = 0; + if (args->names) { + name = build_const_path(rb_ary_last(0, 0, args->names), args->last); + } + set_sub_temporary_name_foreach(mod, args, name); + return Qtrue; +} + +static VALUE +set_sub_temporary_name_topmost(VALUE mod, VALUE data, int recursive) +{ + if (recursive) return Qfalse; + + struct sub_temporary_name_args *args = (void *)data; + VALUE name = args->names; + if (name) { + args->names = rb_ary_hidden_new(0); + } + set_sub_temporary_name_foreach(mod, args, name); + return Qtrue; +} + +static enum rb_id_table_iterator_result +set_sub_temporary_name_i(ID id, VALUE val, void *data) +{ + val = ((rb_const_entry_t *)val)->value; + if (rb_namespace_p(val) && !RCLASS_EXT(val)->permanent_classpath) { + VALUE arg = (VALUE)data; + struct sub_temporary_name_args *args = data; + args->last = id; + rb_exec_recursive_paired(set_sub_temporary_name_recursive, val, arg, arg); + } + return ID_TABLE_CONTINUE; +} + +static void +set_sub_temporary_name_foreach(VALUE mod, struct sub_temporary_name_args *args, VALUE name) +{ + RCLASS_SET_CLASSPATH(mod, name, FALSE); + struct rb_id_table *tbl = RCLASS_CONST_TBL(mod); + if (!tbl) return; + if (!name) { + rb_id_table_foreach(tbl, set_sub_temporary_name_i, args); + } + else { + long names_len = RARRAY_LEN(args->names); // paranoiac check? + rb_ary_push(args->names, name); + rb_id_table_foreach(tbl, set_sub_temporary_name_i, args); + rb_ary_set_len(args->names, names_len); + } +} + +static void +set_sub_temporary_name(VALUE mod, VALUE name) +{ + struct sub_temporary_name_args args = {name}; + VALUE arg = (VALUE)&args; + rb_exec_recursive_paired(set_sub_temporary_name_topmost, mod, arg, arg); +} + /* * call-seq: * mod.set_temporary_name(string) -> self @@ -215,8 +289,11 @@ rb_mod_set_temporary_name(VALUE mod, VALUE name) if (NIL_P(name)) { // Set the temporary classpath to NULL (anonymous): - RCLASS_SET_CLASSPATH(mod, 0, FALSE); - } else { + RB_VM_LOCK_ENTER(); + set_sub_temporary_name(mod, 0); + RB_VM_LOCK_LEAVE(); + } + else { // Ensure the name is a string: StringValue(name); @@ -231,7 +308,9 @@ rb_mod_set_temporary_name(VALUE mod, VALUE name) name = rb_str_new_frozen(name); // Set the temporary classpath to the given name: - RCLASS_SET_CLASSPATH(mod, name, FALSE); + RB_VM_LOCK_ENTER(); + set_sub_temporary_name(mod, name); + RB_VM_LOCK_LEAVE(); } return mod; diff --git a/version.h b/version.h index 7d9016b4498852..b9f9eee68d05f4 100644 --- a/version.h +++ b/version.h @@ -11,7 +11,7 @@ # define RUBY_VERSION_MINOR RUBY_API_VERSION_MINOR #define RUBY_VERSION_TEENY 7 #define RUBY_RELEASE_DATE RUBY_RELEASE_YEAR_STR"-"RUBY_RELEASE_MONTH_STR"-"RUBY_RELEASE_DAY_STR -#define RUBY_PATCHLEVEL 137 +#define RUBY_PATCHLEVEL 138 #include "ruby/version.h" #include "ruby/internal/abi.h" From 51dee044c1cb079a463118c5113ae9fdf96e463e Mon Sep 17 00:00:00 2001 From: nagachika Date: Sun, 30 Mar 2025 12:11:59 +0900 Subject: [PATCH 29/41] merge revision(s) 5f77f9bea61fb4cc8447a76e191fdfb28f076862: [Backport #21195] Fix handling of `error`/`errno` in `io_internal_wait`. (#12961) [Bug #21195] --- io.c | 10 ++++++++-- test/ruby/test_io.rb | 26 ++++++++++++++++++++++++++ version.h | 2 +- 3 files changed, 35 insertions(+), 3 deletions(-) diff --git a/io.c b/io.c index 7f23656049501a..b4b262b6ac808e 100644 --- a/io.c +++ b/io.c @@ -1156,8 +1156,14 @@ io_internal_wait(VALUE thread, rb_io_t *fptr, int error, int events, struct time return -1; } - errno = error; - return -1; + // If there was an error BEFORE we started waiting, return it: + if (error) { + errno = error; + return -1; + } else { + // Otherwise, whatever error was generated by `nogvl_wait_for` is the one we want: + return ready; + } } static VALUE diff --git a/test/ruby/test_io.rb b/test/ruby/test_io.rb index 16de2e8a76a955..760279ca3d46f2 100644 --- a/test/ruby/test_io.rb +++ b/test/ruby/test_io.rb @@ -4297,4 +4297,30 @@ def test_stdout_to_closed_pipe end end end + + def test_blocking_timeout + assert_separately([], <<~'RUBY') + IO.pipe do |r, w| + trap(:INT) do + w.puts "INT" + end + + main = Thread.current + thread = Thread.new do + # Wait until the main thread has entered `$stdin.gets`: + Thread.pass until main.status == 'sleep' + + # Cause an interrupt while handling `$stdin.gets`: + Process.kill :INT, $$ + end + + r.timeout = 1 + assert_equal("INT", r.gets.chomp) + rescue IO::TimeoutError + # Ignore - some platforms don't support interrupting `gets`. + ensure + thread&.join + end + RUBY + end end diff --git a/version.h b/version.h index b9f9eee68d05f4..31b5671956d5a9 100644 --- a/version.h +++ b/version.h @@ -11,7 +11,7 @@ # define RUBY_VERSION_MINOR RUBY_API_VERSION_MINOR #define RUBY_VERSION_TEENY 7 #define RUBY_RELEASE_DATE RUBY_RELEASE_YEAR_STR"-"RUBY_RELEASE_MONTH_STR"-"RUBY_RELEASE_DAY_STR -#define RUBY_PATCHLEVEL 138 +#define RUBY_PATCHLEVEL 139 #include "ruby/version.h" #include "ruby/internal/abi.h" From ca0238353dd594c1012b7263b83e0c7eeb882cf4 Mon Sep 17 00:00:00 2001 From: Hiroshi SHIBATA Date: Tue, 1 Apr 2025 15:20:17 +0900 Subject: [PATCH 30/41] [rubygems/rubygems] Bump up minimum required version for cmake 4 https://github.com/rubygems/rubygems/commit/3e77caeddf --- test/rubygems/test_gem_ext_cmake_builder.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/rubygems/test_gem_ext_cmake_builder.rb b/test/rubygems/test_gem_ext_cmake_builder.rb index 5f886af05fcae0..b4cf8a8443c99b 100644 --- a/test/rubygems/test_gem_ext_cmake_builder.rb +++ b/test/rubygems/test_gem_ext_cmake_builder.rb @@ -29,7 +29,7 @@ def setup def test_self_build File.open File.join(@ext, "CMakeLists.txt"), "w" do |cmakelists| cmakelists.write <<-EO_CMAKE -cmake_minimum_required(VERSION 2.6) +cmake_minimum_required(VERSION 3.5) project(self_build NONE) install (FILES test.txt DESTINATION bin) EO_CMAKE From 3d8a66568e8106b367665d716e0d3c8c8208aa07 Mon Sep 17 00:00:00 2001 From: nagachika Date: Wed, 2 Apr 2025 21:16:22 +0900 Subject: [PATCH 31/41] merge revision(s) d78ff6a767ca813ac5fa178dd7611f20a993c191: [Backport #20984] [Bug #20984] Fix test with locale encoding --- test/ruby/test_env.rb | 11 ++++++----- version.h | 2 +- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/test/ruby/test_env.rb b/test/ruby/test_env.rb index 466d8d9d122c25..949913b5901b92 100644 --- a/test/ruby/test_env.rb +++ b/test/ruby/test_env.rb @@ -2,7 +2,9 @@ require 'test/unit' class TestEnv < Test::Unit::TestCase - IGNORE_CASE = /bccwin|mswin|mingw/ =~ RUBY_PLATFORM + windows = /bccwin|mswin|mingw/ =~ RUBY_PLATFORM + IGNORE_CASE = windows + ENCODING = windows ? Encoding::UTF_8 : Encoding.find("locale") PATH_ENV = "PATH" INVALID_ENVVARS = [ "foo\0bar", @@ -357,7 +359,7 @@ def test_inspect_encoding ENV.clear key = "VAR\u{e5 e1 e2 e4 e3 101 3042}" ENV[key] = "foo" - assert_equal(%{{"VAR\u{e5 e1 e2 e4 e3 101 3042}"=>"foo"}}, ENV.inspect) + assert_equal(%{{#{(key.encode(ENCODING) rescue key.b).inspect}=>"foo"}}, ENV.inspect) end def test_to_a @@ -410,8 +412,7 @@ def test_assoc assert_equal("foo", v) end assert_invalid_env {|var| ENV.assoc(var)} - encoding = /mswin|mingw/ =~ RUBY_PLATFORM ? Encoding::UTF_8 : Encoding.find("locale") - assert_equal(encoding, v.encoding) + assert_equal(ENCODING, v.encoding) end def test_has_value2 @@ -524,7 +525,7 @@ def test_huge_value assert_equal(huge_value, ENV["foo"]) end - if /mswin|mingw/ =~ RUBY_PLATFORM + if windows def windows_version @windows_version ||= %x[ver][/Version (\d+)/, 1].to_i end diff --git a/version.h b/version.h index 31b5671956d5a9..5217d920d354ab 100644 --- a/version.h +++ b/version.h @@ -11,7 +11,7 @@ # define RUBY_VERSION_MINOR RUBY_API_VERSION_MINOR #define RUBY_VERSION_TEENY 7 #define RUBY_RELEASE_DATE RUBY_RELEASE_YEAR_STR"-"RUBY_RELEASE_MONTH_STR"-"RUBY_RELEASE_DAY_STR -#define RUBY_PATCHLEVEL 139 +#define RUBY_PATCHLEVEL 140 #include "ruby/version.h" #include "ruby/internal/abi.h" From 31c295ef28fc678d8416f1f35726ac43d470d1d3 Mon Sep 17 00:00:00 2001 From: Hiroshi SHIBATA Date: Thu, 3 Apr 2025 09:40:11 +0900 Subject: [PATCH 32/41] Enforce to use CMake 3 because CMake 4 is not compatible to build libyaml via vcpkg --- .github/workflows/windows.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/windows.yml b/.github/workflows/windows.yml index 6311854e256047..cdbaf88c58eeb6 100644 --- a/.github/workflows/windows.yml +++ b/.github/workflows/windows.yml @@ -117,6 +117,7 @@ jobs: run: | iex "& {$(irm get.scoop.sh)} -RunAsAdmin" Join-Path (Resolve-Path ~).Path "scoop\shims" >> $Env:GITHUB_PATH + scoop install vcpkg cmake@3.31.6 shell: pwsh - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 From c48219e2d738faa388e61361c0549f7addbfacfe Mon Sep 17 00:00:00 2001 From: Hiroshi SHIBATA Date: Thu, 3 Apr 2025 13:04:31 +0900 Subject: [PATCH 33/41] f7059af50a31 is also required at ractor_core.h --- ractor_core.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ractor_core.h b/ractor_core.h index 36c0e91c7aeef5..e607cf5f2f0ca6 100644 --- a/ractor_core.h +++ b/ractor_core.h @@ -315,7 +315,7 @@ rb_ractor_set_current_ec_(rb_ractor_t *cr, rb_execution_context_t *ec, const cha { #ifdef RB_THREAD_LOCAL_SPECIFIER -# ifdef __APPLE__ +# if defined(__arm64__) || defined(__aarch64__) rb_current_ec_set(ec); # else ruby_current_ec = ec; From 7065e60318c970655eb561829a2071c310b67e2d Mon Sep 17 00:00:00 2001 From: Hiroshi SHIBATA Date: Thu, 3 Apr 2025 14:18:55 +0900 Subject: [PATCH 34/41] Use IPv4 for test server because TestNetHTTPS is failing with s390x https://rubyci.s3.amazonaws.com/s390x/ruby-3.2/log/20250403T005659Z.fail.html.gz --- test/net/http/test_http.rb | 4 ++-- test/net/http/test_https.rb | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/test/net/http/test_http.rb b/test/net/http/test_http.rb index 53092ee0e8e194..55fc983a0f543a 100644 --- a/test/net/http/test_http.rb +++ b/test/net/http/test_http.rb @@ -1249,7 +1249,7 @@ def @server.run(sock) class TestNetHTTPLocalBind < Test::Unit::TestCase CONFIG = { - 'host' => 'localhost', + 'host' => '127.0.0.1', 'proxy_host' => nil, 'proxy_port' => nil, } @@ -1286,7 +1286,7 @@ def test_bind_to_local_port class TestNetHTTPForceEncoding < Test::Unit::TestCase CONFIG = { - 'host' => 'localhost', + 'host' => '127.0.0.1', 'proxy_host' => nil, 'proxy_port' => nil, } diff --git a/test/net/http/test_https.rb b/test/net/http/test_https.rb index c0d66ba3542c09..0477f7df638fc5 100644 --- a/test/net/http/test_https.rb +++ b/test/net/http/test_https.rb @@ -23,7 +23,7 @@ def self.read_fixture(key) TEST_STORE = OpenSSL::X509::Store.new.tap {|s| s.add_cert(CA_CERT) } CONFIG = { - 'host' => HOST, + 'host' => HOST_IP, 'proxy_host' => nil, 'proxy_port' => nil, 'ssl_enable' => true, From f2ee22f32d3b4919b9a5b62a81b544019383ef3a Mon Sep 17 00:00:00 2001 From: Hiroshi SHIBATA Date: Thu, 3 Apr 2025 19:07:08 +0900 Subject: [PATCH 35/41] Extend open_timeout for test failure on s390x https://rubyci.s3.amazonaws.com/s390x/ruby-master/log/20250403T060004Z.fail.html.gz --- test/net/http/test_http.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/net/http/test_http.rb b/test/net/http/test_http.rb index 55fc983a0f543a..d45d26ad464874 100644 --- a/test/net/http/test_http.rb +++ b/test/net/http/test_http.rb @@ -549,7 +549,7 @@ def test_timeout_during_HTTP_session_write conn = Net::HTTP.new('localhost', port) conn.write_timeout = EnvUtil.apply_timeout_scale(0.01) conn.read_timeout = EnvUtil.apply_timeout_scale(0.01) if windows? - conn.open_timeout = EnvUtil.apply_timeout_scale(0.1) + conn.open_timeout = EnvUtil.apply_timeout_scale(1) th = Thread.new do err = !windows? ? Net::WriteTimeout : Net::ReadTimeout @@ -575,7 +575,7 @@ def test_timeout_during_non_chunked_streamed_HTTP_session_write conn = Net::HTTP.new('localhost', port) conn.write_timeout = 0.01 conn.read_timeout = 0.01 if windows? - conn.open_timeout = 0.1 + conn.open_timeout = 1 req = Net::HTTP::Post.new('/') data = "a"*50_000_000 From a1679f0d83845a35116d4e40bba4783346c8d7dc Mon Sep 17 00:00:00 2001 From: Hiroshi SHIBATA Date: Thu, 3 Apr 2025 19:30:24 +0900 Subject: [PATCH 36/41] Use EnvUtil.apply_timeout_scale --- test/net/http/test_http.rb | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/test/net/http/test_http.rb b/test/net/http/test_http.rb index d45d26ad464874..eb7d3e672ca2eb 100644 --- a/test/net/http/test_http.rb +++ b/test/net/http/test_http.rb @@ -573,9 +573,9 @@ def test_timeout_during_non_chunked_streamed_HTTP_session_write port = server.addr[1] conn = Net::HTTP.new('localhost', port) - conn.write_timeout = 0.01 - conn.read_timeout = 0.01 if windows? - conn.open_timeout = 1 + conn.write_timeout = EnvUtil.apply_timeout_scale(0.01) + conn.read_timeout = EnvUtil.apply_timeout_scale(0.01) if windows? + conn.open_timeout = EnvUtil.apply_timeout_scale(1) req = Net::HTTP::Post.new('/') data = "a"*50_000_000 From 7c315e23983a35d29108d9ba8c914d6320254d43 Mon Sep 17 00:00:00 2001 From: nagachika Date: Sun, 6 Apr 2025 11:24:36 +0900 Subject: [PATCH 37/41] merge revision(s) 117d6e145a0270ab8fc9134403519ef13b9ebb24: [Backport #21027] [ruby/prism] Fix `not` receiver `not foo` should be `!foo` `not()` should be `!nil` Fixes [Bug #21027] https://github.com/ruby/prism/commit/871ed4b462 --- prism/prism.c | 5 +++-- version.h | 2 +- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/prism/prism.c b/prism/prism.c index 79258386d60316..b897d9cdd7abe3 100644 --- a/prism/prism.c +++ b/prism/prism.c @@ -15254,11 +15254,12 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power, b accept1(parser, PM_TOKEN_NEWLINE); if (accept1(parser, PM_TOKEN_PARENTHESIS_LEFT)) { - arguments.opening_loc = PM_LOCATION_TOKEN_VALUE(&parser->previous); + pm_token_t lparen = parser->previous; if (accept1(parser, PM_TOKEN_PARENTHESIS_RIGHT)) { - arguments.closing_loc = PM_LOCATION_TOKEN_VALUE(&parser->previous); + receiver = (pm_node_t *) pm_parentheses_node_create(parser, &lparen, NULL, &parser->previous); } else { + arguments.closing_loc = PM_LOCATION_TOKEN_VALUE(&parser->previous); receiver = parse_expression(parser, PM_BINDING_POWER_COMPOSITION, true, PM_ERR_NOT_EXPRESSION); pm_conditional_predicate(receiver); diff --git a/version.h b/version.h index 5217d920d354ab..2715555ea3c88e 100644 --- a/version.h +++ b/version.h @@ -11,7 +11,7 @@ # define RUBY_VERSION_MINOR RUBY_API_VERSION_MINOR #define RUBY_VERSION_TEENY 7 #define RUBY_RELEASE_DATE RUBY_RELEASE_YEAR_STR"-"RUBY_RELEASE_MONTH_STR"-"RUBY_RELEASE_DAY_STR -#define RUBY_PATCHLEVEL 140 +#define RUBY_PATCHLEVEL 141 #include "ruby/version.h" #include "ruby/internal/abi.h" From 5640fea8aada2380145375a7f9eac2b979fe1258 Mon Sep 17 00:00:00 2001 From: nagachika Date: Sun, 6 Apr 2025 13:42:21 +0900 Subject: [PATCH 38/41] Update prism test snapshots. This is follow-up for 7c315e23983a35d29108d9ba8c914d6320254d43. --- test/prism/snapshots/not.txt | 6 +++--- test/prism/snapshots/seattlerb/bug_not_parens.txt | 2 +- test/prism/snapshots/whitequark/not.txt | 12 ++++++++---- 3 files changed, 12 insertions(+), 8 deletions(-) diff --git a/test/prism/snapshots/not.txt b/test/prism/snapshots/not.txt index 572e7b13ca5658..5933a860b0668f 100644 --- a/test/prism/snapshots/not.txt +++ b/test/prism/snapshots/not.txt @@ -77,7 +77,7 @@ │ ├── call_operator_loc: ∅ │ ├── name: :! │ ├── message_loc: (3,0)-(3,3) = "not" - │ ├── opening_loc: (3,3)-(3,4) = "(" + │ ├── opening_loc: ∅ │ ├── arguments: ∅ │ ├── closing_loc: (3,15)-(3,16) = ")" │ └── block: ∅ @@ -249,7 +249,7 @@ │ ├── call_operator_loc: ∅ │ ├── name: :! │ ├── message_loc: (22,0)-(22,3) = "not" - │ ├── opening_loc: (22,3)-(22,4) = "(" + │ ├── opening_loc: ∅ │ ├── arguments: ∅ │ ├── closing_loc: (25,0)-(25,1) = ")" │ └── block: ∅ @@ -269,7 +269,7 @@ │ ├── call_operator_loc: ∅ │ ├── name: :! │ ├── message_loc: (27,0)-(27,3) = "not" - │ ├── opening_loc: (27,3)-(27,4) = "(" + │ ├── opening_loc: ∅ │ ├── arguments: ∅ │ ├── closing_loc: (33,2)-(33,3) = ")" │ └── block: ∅ diff --git a/test/prism/snapshots/seattlerb/bug_not_parens.txt b/test/prism/snapshots/seattlerb/bug_not_parens.txt index c5157a0ed9ffe9..a82ab6ed4da024 100644 --- a/test/prism/snapshots/seattlerb/bug_not_parens.txt +++ b/test/prism/snapshots/seattlerb/bug_not_parens.txt @@ -19,7 +19,7 @@ ├── call_operator_loc: ∅ ├── name: :! ├── message_loc: (1,0)-(1,3) = "not" - ├── opening_loc: (1,3)-(1,4) = "(" + ├── opening_loc: ∅ ├── arguments: ∅ ├── closing_loc: (1,5)-(1,6) = ")" └── block: ∅ diff --git a/test/prism/snapshots/whitequark/not.txt b/test/prism/snapshots/whitequark/not.txt index 95984ddc06b01a..43e9305b8f1cdf 100644 --- a/test/prism/snapshots/whitequark/not.txt +++ b/test/prism/snapshots/whitequark/not.txt @@ -25,13 +25,17 @@ │ └── block: ∅ ├── @ CallNode (location: (3,0)-(3,5)) │ ├── flags: ∅ - │ ├── receiver: ∅ + │ ├── receiver: + │ │ @ ParenthesesNode (location: (3,3)-(3,5)) + │ │ ├── body: ∅ + │ │ ├── opening_loc: (3,3)-(3,4) = "(" + │ │ └── closing_loc: (3,4)-(3,5) = ")" │ ├── call_operator_loc: ∅ │ ├── name: :! │ ├── message_loc: (3,0)-(3,3) = "not" - │ ├── opening_loc: (3,3)-(3,4) = "(" + │ ├── opening_loc: ∅ │ ├── arguments: ∅ - │ ├── closing_loc: (3,4)-(3,5) = ")" + │ ├── closing_loc: ∅ │ └── block: ∅ └── @ CallNode (location: (5,0)-(5,8)) ├── flags: ∅ @@ -49,7 +53,7 @@ ├── call_operator_loc: ∅ ├── name: :! ├── message_loc: (5,0)-(5,3) = "not" - ├── opening_loc: (5,3)-(5,4) = "(" + ├── opening_loc: ∅ ├── arguments: ∅ ├── closing_loc: (5,7)-(5,8) = ")" └── block: ∅ From a67e9e41846cdadad9bb2d9e9d10223c52253898 Mon Sep 17 00:00:00 2001 From: nagachika Date: Mon, 7 Apr 2025 21:19:10 +0900 Subject: [PATCH 39/41] merge revision(s) 3a7b9ca93b91dcc086b9ac8b9957e59268f9493b: [Backport #21217] Fix `Integer.sqrt` to never exceed actual value `Integer.sqrt` uses `sqrt(3)` from libm for small values. This method must return a value less than or equal to the actual integer square root, but libm's sqrt does not always guarantee that. This change corrects that by decrementing the result if necessary. Fixes [Bug #21217] --- numeric.c | 6 +++++- test/ruby/test_integer.rb | 4 ++++ version.h | 2 +- 3 files changed, 10 insertions(+), 2 deletions(-) diff --git a/numeric.c b/numeric.c index 03b336d9b720f1..41891acf1a82d7 100644 --- a/numeric.c +++ b/numeric.c @@ -5844,7 +5844,11 @@ prefix##_isqrt(argtype n) \ while ((t = n/x) < (argtype)x) x = (rettype)((x + t) >> 1); \ return x; \ } \ - return (rettype)sqrt(argtype##_TO_DOUBLE(n)); \ + rettype x = (rettype)sqrt(argtype##_TO_DOUBLE(n)); \ + /* libm sqrt may returns a larger approximation than actual. */ \ + /* Our isqrt always returns a smaller approximation. */ \ + if (x * x > n) x--; \ + return x; \ } #if SIZEOF_LONG*CHAR_BIT > DBL_MANT_DIG diff --git a/test/ruby/test_integer.rb b/test/ruby/test_integer.rb index dc68b4e7a4ecb6..1f820b28e9226e 100644 --- a/test/ruby/test_integer.rb +++ b/test/ruby/test_integer.rb @@ -709,6 +709,10 @@ def test_square_root assert_equal(x, Integer.sqrt(x ** 2), "[ruby-core:95453]") end + def test_bug_21217 + assert_equal(0x10000 * 2**10, Integer.sqrt(0x100000008 * 2**20)) + end + def test_fdiv assert_equal(1.0, 1.fdiv(1)) assert_equal(0.5, 1.fdiv(2)) diff --git a/version.h b/version.h index 2715555ea3c88e..358336af388232 100644 --- a/version.h +++ b/version.h @@ -11,7 +11,7 @@ # define RUBY_VERSION_MINOR RUBY_API_VERSION_MINOR #define RUBY_VERSION_TEENY 7 #define RUBY_RELEASE_DATE RUBY_RELEASE_YEAR_STR"-"RUBY_RELEASE_MONTH_STR"-"RUBY_RELEASE_DAY_STR -#define RUBY_PATCHLEVEL 141 +#define RUBY_PATCHLEVEL 142 #include "ruby/version.h" #include "ruby/internal/abi.h" From 4ca521e91342165ed35cb12c9868f10e2a6aa07c Mon Sep 17 00:00:00 2001 From: nagachika Date: Wed, 9 Apr 2025 17:27:37 +0900 Subject: [PATCH 40/41] merge revision(s) 06919949a60b42a8f30e8bd0cb075e17b05eebcd, 51bc992822f9108ad64de32d300e1cefd0e2da59, 42daa6c2a2b49b4e45f40736e25c7d182860f24a: [Backport #21141] [Bug #21141] [DOC] Clarify what time is in UTC [Bug #21141] [DOC] Refine description of `Time#utc?` [Bug #21141] [DOC] Fix indentation --- time.c | 11 +++++++++++ version.h | 2 +- 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/time.c b/time.c index 082ddd43b6885c..0e45d522acb333 100644 --- a/time.c +++ b/time.c @@ -3996,10 +3996,21 @@ time_eql(VALUE time1, VALUE time2) * now = Time.now * # => 2022-08-18 10:24:13.5398485 -0500 * now.utc? # => false + * now.getutc.utc? # => true * utc = Time.utc(2000, 1, 1, 20, 15, 1) * # => 2000-01-01 20:15:01 UTC * utc.utc? # => true * + * +Time+ objects created with these methods are considered to be in + * UTC: + * + * * Time.utc + * * Time#utc + * * Time#getutc + * + * Objects created in other ways will not be treated as UTC even if + * the environment variable "TZ" is "UTC". + * * Related: Time.utc. */ diff --git a/version.h b/version.h index 358336af388232..408f6565bfdc76 100644 --- a/version.h +++ b/version.h @@ -11,7 +11,7 @@ # define RUBY_VERSION_MINOR RUBY_API_VERSION_MINOR #define RUBY_VERSION_TEENY 7 #define RUBY_RELEASE_DATE RUBY_RELEASE_YEAR_STR"-"RUBY_RELEASE_MONTH_STR"-"RUBY_RELEASE_DAY_STR -#define RUBY_PATCHLEVEL 142 +#define RUBY_PATCHLEVEL 143 #include "ruby/version.h" #include "ruby/internal/abi.h" From b200bad6cd40d08e9f33b93e1a85c270b337867c Mon Sep 17 00:00:00 2001 From: nagachika Date: Wed, 9 Apr 2025 18:23:04 +0900 Subject: [PATCH 41/41] bump teeny --- version.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/version.h b/version.h index 408f6565bfdc76..e8b1c04d693918 100644 --- a/version.h +++ b/version.h @@ -9,9 +9,9 @@ */ # define RUBY_VERSION_MAJOR RUBY_API_VERSION_MAJOR # define RUBY_VERSION_MINOR RUBY_API_VERSION_MINOR -#define RUBY_VERSION_TEENY 7 +#define RUBY_VERSION_TEENY 8 #define RUBY_RELEASE_DATE RUBY_RELEASE_YEAR_STR"-"RUBY_RELEASE_MONTH_STR"-"RUBY_RELEASE_DAY_STR -#define RUBY_PATCHLEVEL 143 +#define RUBY_PATCHLEVEL 144 #include "ruby/version.h" #include "ruby/internal/abi.h"