From cadca9f67eba9e101558aa32594646c3ece17c31 Mon Sep 17 00:00:00 2001 From: Samuel Giddins Date: Thu, 24 Aug 2023 09:23:02 -0700 Subject: [PATCH] [rubygems/rubygems] All rubies working with different time zones Tested with: `ruby -e 'trap("INT") { exit 1 }; TZ=%w[UTC +0000 -0000]; RUBY=%w[ruby-2.7 ruby-3.2.2 jruby-9.4 truffleruby-22 truffleruby-23]; TZ.product(RUBY).each { |t, r| puts ?**120, "TZ=#{t} RUBY=#{r}", "*"*120; system({"TZ"=>t,"RUBY"=>r}, *ARGV) }' zsh -lic 'chruby $RUBY; ruby -vw -Ilib test/rubygems/test_gem_safe_marshal.rb --verbose=progress'` https://github.com/rubygems/rubygems/commit/6192005afb --- lib/rubygems/safe_marshal.rb | 2 +- lib/rubygems/safe_marshal/visitors/to_ruby.rb | 10 ++++--- test/rubygems/test_gem_safe_marshal.rb | 27 ++++++++++++++++--- 3 files changed, 30 insertions(+), 9 deletions(-) diff --git a/lib/rubygems/safe_marshal.rb b/lib/rubygems/safe_marshal.rb index d308f2d65f..b81d1a0a47 100644 --- a/lib/rubygems/safe_marshal.rb +++ b/lib/rubygems/safe_marshal.rb @@ -42,7 +42,7 @@ module Gem private_constant :PERMITTED_SYMBOLS PERMITTED_IVARS = { - "String" => %w[E @taguri @debug_created_info], + "String" => %w[E encoding @taguri @debug_created_info], "Time" => %w[ offset zone nano_num nano_den submicro @_zone @marshal_with_utc_coercion diff --git a/lib/rubygems/safe_marshal/visitors/to_ruby.rb b/lib/rubygems/safe_marshal/visitors/to_ruby.rb index 81c5c536d5..d1e6e8669d 100644 --- a/lib/rubygems/safe_marshal/visitors/to_ruby.rb +++ b/lib/rubygems/safe_marshal/visitors/to_ruby.rb @@ -54,7 +54,6 @@ module Gem::SafeMarshal end def visit_Gem_SafeMarshal_Elements_WithIvars(e) - idx = 0 object_offset = @objects.size @stack << "object" object = visit(e.object) @@ -104,8 +103,9 @@ module Gem::SafeMarshal if zone require "time" - zone = "+0000" if zone == "UTC" && offset == 0 - call_method(Time, :force_zone!, object, zone, offset) + transformed_zone = zone + transformed_zone = "+0000" if ["UTC", "Z"].include?(zone) && offset == 0 + call_method(Time, :force_zone!, object, transformed_zone, offset) elsif offset object = object.localtime offset end @@ -131,8 +131,10 @@ module Gem::SafeMarshal when FalseClass enc = "US-ASCII" else - enc = v + raise FormatError, "Unexpected value for String :E #{v.inspect}" end + when :encoding + enc = v else next false end diff --git a/test/rubygems/test_gem_safe_marshal.rb b/test/rubygems/test_gem_safe_marshal.rb index 8b6ef5d186..5a381b0107 100644 --- a/test/rubygems/test_gem_safe_marshal.rb +++ b/test/rubygems/test_gem_safe_marshal.rb @@ -36,8 +36,16 @@ class TestGemSafeMarshal < Gem::TestCase end def test_string_with_encoding - assert_safe_load_as String.new("abc", encoding: "US-ASCII") - assert_safe_load_as String.new("abc", encoding: "UTF-8") + [ + String.new("abc", encoding: "US-ASCII"), + String.new("abc", encoding: "UTF-8"), + String.new("abc", encoding: "Windows-1256"), + String.new("abc", encoding: Encoding::BINARY), + String.new("abc", encoding: "UTF-32"), + ].each do |s| + assert_safe_load_as s, additional_methods: [:encoding] + assert_safe_load_as [s, s], additional_methods: [->(a) { a.map(&:encoding) }] + end end def test_string_with_ivar @@ -75,7 +83,12 @@ class TestGemSafeMarshal < Gem::TestCase Time.at(secs, 1.001, :nanosecond), Time.at(secs, 1.00001, :nanosecond), Time.at(secs, 1.00001, :nanosecond), - ].each_with_index do |t, i| + ].tap do |times| + times.concat [ + Time.at(secs, in: "UTC"), + Time.at(secs, in: "Z"), + ] unless RUBY_ENGINE == "truffleruby" && RUBY_ENGINE_VERSION < "23" + end.each_with_index do |t, i| define_method("test_time_#{i} #{t.inspect}") do pend "Marshal.load of Time with custom zone is broken before Truffleruby 23" if t.zone.nil? && RUBY_ENGINE == "truffleruby" && RUBY_ENGINE_VERSION < "23" @@ -167,7 +180,13 @@ class TestGemSafeMarshal < Gem::TestCase assert_equal x.to_s, safe_loaded.to_s, "should have equal to_s" assert_equal x.inspect, safe_loaded.inspect, "should have equal inspect" additional_methods.each do |m| - assert_equal loaded.send(m), safe_loaded.send(m), "should have equal #{m}" + if m.is_a?(Proc) + call = m + else + call = ->(obj) { obj.__send__(m) } + end + + assert_equal call[loaded], call[safe_loaded], "should have equal #{m}" end assert_equal Marshal.dump(loaded), Marshal.dump(safe_loaded), "should Marshal.dump the same" end