diff options
author | Samuel Giddins <[email protected]> | 2023-08-24 12:31:43 -0700 |
---|---|---|
committer | git <[email protected]> | 2023-09-20 02:03:04 +0000 |
commit | 843c83ee5f8f4c26b70d7873df0c3d23de597b4c (patch) | |
tree | b55b6c7d7d40ecc4efa72411109444900f2c95f2 | |
parent | f4a5fac0d2671ec98f50a561eefd4ca3702f7cb1 (diff) |
[rubygems/rubygems] Give up, load Time via Marshal.load
https://github.com/rubygems/rubygems/commit/6c92ba2ba3
-rw-r--r-- | lib/rubygems/safe_marshal/visitors/to_ruby.rb | 59 | ||||
-rw-r--r-- | test/rubygems/test_gem_safe_marshal.rb | 145 |
2 files changed, 149 insertions, 55 deletions
diff --git a/lib/rubygems/safe_marshal/visitors/to_ruby.rb b/lib/rubygems/safe_marshal/visitors/to_ruby.rb index d1e6e8669d..147141c2c5 100644 --- a/lib/rubygems/safe_marshal/visitors/to_ruby.rb +++ b/lib/rubygems/safe_marshal/visitors/to_ruby.rb @@ -62,62 +62,29 @@ module Gem::SafeMarshal case e.object when Elements::UserDefined if object.class == ::Time - offset = zone = nano_num = nano_den = submicro = nil + internal = [] + ivars.reject! do |k, v| case k - when :offset - offset = v - when :zone - zone = v - when :nano_num - nano_num = v - when :nano_den - nano_den = v - when :submicro - submicro = v + when :offset, :zone, :nano_num, :nano_den, :submicro + internal << [k, v] + true else - next false + false end - true end - if (nano_den || nano_num) && !(nano_den && nano_num) - raise FormatError, "Must have all of nano_den, nano_num for Time #{e.pretty_inspect}" - elsif nano_den && nano_num - if RUBY_ENGINE == "jruby" - nano = Rational(nano_num, nano_den * 1_000_000_000) - object = Time.at(object.to_i + nano + object.subsec) - elsif RUBY_ENGINE == "truffleruby" - if RUBY_ENGINE_VERSION >= "23.0.0" - object = Time.at(object.to_i, Rational(nano_num, nano_den).to_i, :nanosecond) - else - object = object.floor + Rational(nano_num, nano_den * 1_000_000_000) - end - else # assume "ruby" - nano = Rational(nano_num, nano_den) - nsec, subnano = nano.divmod(1) - nano = nsec + subnano - object = Time.at(object.to_r, nano, :nanosecond) - end - end + s = e.object.binary_string - if zone - require "time" - 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 + marshal_string = "\x04\bIu:\tTime#{(s.size + 5).chr}#{s.b}".b + + marshal_string << (internal.size + 5).chr - if RUBY_ENGINE == "truffleruby" && RUBY_ENGINE_VERSION < "23.0.0" - ivars << [:@offset, offset] - ivars << [:@zone, zone] - ivars << [:@nano_num, nano_num] if nano_num - ivars << [:@nano_den, nano_den] if nano_den + internal.each do |k, v| + marshal_string << ":#{(k.size + 5).chr}#{k}#{Marshal.dump(v)[2..-1]}" end - @objects[object_offset] = object + object = @objects[object_offset] = Marshal.load(marshal_string) end when Elements::String enc = nil diff --git a/test/rubygems/test_gem_safe_marshal.rb b/test/rubygems/test_gem_safe_marshal.rb index fb272877f5..d123ad5dc4 100644 --- a/test/rubygems/test_gem_safe_marshal.rb +++ b/test/rubygems/test_gem_safe_marshal.rb @@ -6,6 +6,120 @@ require "date" require "rubygems/safe_marshal" class TestGemSafeMarshal < Gem::TestCase + define_method("test_safe_load_marshal Date #<Date: 1994-12-09 ((2449696j,0s,0n),+0s,2299161j)>") { assert_safe_load_marshal "\x04\bU:\tDate[\vi\x00i\x03 a%i\x00i\x00i\x00f\f2299161" } + define_method("test_safe_load_marshal Float 0.0") { assert_safe_load_marshal "\x04\bf\x060" } + define_method("test_safe_load_marshal Float -0.0") { assert_safe_load_marshal "\x04\bf\a-0" } + define_method("test_safe_load_marshal Float Infinity") { assert_safe_load_marshal "\x04\bf\binf" } + define_method("test_safe_load_marshal Float -Infinity") { assert_safe_load_marshal "\x04\bf\t-inf" } + define_method("test_safe_load_marshal Float NaN") { assert_safe_load_marshal "\x04\bf\bnan", equality: false } + define_method("test_safe_load_marshal Float 1.1") { assert_safe_load_marshal "\x04\bf\b1.1" } + define_method("test_safe_load_marshal Float -1.1") { assert_safe_load_marshal "\x04\bf\t-1.1" } + define_method("test_safe_load_marshal Float 30000000.0") { assert_safe_load_marshal "\x04\bf\b3e7" } + define_method("test_safe_load_marshal Float -30000000.0") { assert_safe_load_marshal "\x04\bf\t-3e7" } + define_method("test_safe_load_marshal Gem::Version #<Gem::Version \"1.abc\">") { assert_safe_load_marshal "\x04\bU:\x11Gem::Version[\x06I\"\n1.abc\x06:\x06ET" } + define_method("test_safe_load_marshal Hash {}") { assert_safe_load_marshal "\x04\b}\x00[\x00" } + define_method("test_safe_load_marshal Hash {:runtime=>:development}") { assert_safe_load_marshal "\x04\bI{\x06:\fruntime:\x10development\x06:\n@type[\x00", permitted_ivars: { "Hash" => %w[@type] } } + define_method("test_safe_load_marshal Integer -1") { assert_safe_load_marshal "\x04\bi\xFA" } + define_method("test_safe_load_marshal Integer -1048575") { assert_safe_load_marshal "\x04\bi\xFD\x01\x00\xF0" } + define_method("test_safe_load_marshal Integer -122") { assert_safe_load_marshal "\x04\bi\x81" } + define_method("test_safe_load_marshal Integer -123") { assert_safe_load_marshal "\x04\bi\x80" } + define_method("test_safe_load_marshal Integer -124") { assert_safe_load_marshal "\x04\bi\xFF\x84" } + define_method("test_safe_load_marshal Integer -127") { assert_safe_load_marshal "\x04\bi\xFF\x81" } + define_method("test_safe_load_marshal Integer -128") { assert_safe_load_marshal "\x04\bi\xFF\x80" } + define_method("test_safe_load_marshal Integer -2") { assert_safe_load_marshal "\x04\bi\xF9" } + define_method("test_safe_load_marshal Integer -255") { assert_safe_load_marshal "\x04\bi\xFF\x01" } + define_method("test_safe_load_marshal Integer -256") { assert_safe_load_marshal "\x04\bi\xFF\x00" } + define_method("test_safe_load_marshal Integer -257") { assert_safe_load_marshal "\x04\bi\xFE\xFF\xFE" } + define_method("test_safe_load_marshal Integer -268435455") { assert_safe_load_marshal "\x04\bi\xFC\x01\x00\x00\xF0" } + define_method("test_safe_load_marshal Integer -268435456") { assert_safe_load_marshal "\x04\bi\xFC\x00\x00\x00\xF0" } + define_method("test_safe_load_marshal Integer -3") { assert_safe_load_marshal "\x04\bi\xF8" } + define_method("test_safe_load_marshal Integer -4") { assert_safe_load_marshal "\x04\bi\xF7" } + define_method("test_safe_load_marshal Integer -4294967295") { assert_safe_load_marshal "\x04\bl-\a\xFF\xFF\xFF\xFF" } + define_method("test_safe_load_marshal Integer -4294967296") { assert_safe_load_marshal "\x04\bl-\b\x00\x00\x00\x00\x01\x00" } + define_method("test_safe_load_marshal Integer -5") { assert_safe_load_marshal "\x04\bi\xF6" } + define_method("test_safe_load_marshal Integer -6") { assert_safe_load_marshal "\x04\bi\xF5" } + define_method("test_safe_load_marshal Integer -65535") { assert_safe_load_marshal "\x04\bi\xFE\x01\x00" } + define_method("test_safe_load_marshal Integer -65536") { assert_safe_load_marshal "\x04\bi\xFE\x00\x00" } + define_method("test_safe_load_marshal Integer -9223372036854775807") { assert_safe_load_marshal "\x04\bl-\t\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x7F" } + define_method("test_safe_load_marshal Integer -9223372036854775808") { assert_safe_load_marshal "\x04\bl-\t\x00\x00\x00\x00\x00\x00\x00\x80" } + define_method("test_safe_load_marshal Integer 0") { assert_safe_load_marshal "\x04\bi\x00" } + define_method("test_safe_load_marshal Integer 1") { assert_safe_load_marshal "\x04\bi\x06" } + define_method("test_safe_load_marshal Integer 1048574") { assert_safe_load_marshal "\x04\bi\x03\xFE\xFF\x0F" } + define_method("test_safe_load_marshal Integer 1048575") { assert_safe_load_marshal "\x04\bi\x03\xFF\xFF\x0F" } + define_method("test_safe_load_marshal Integer 1048576") { assert_safe_load_marshal "\x04\bi\x03\x00\x00\x10" } + define_method("test_safe_load_marshal Integer 121") { assert_safe_load_marshal "\x04\bi~" } + define_method("test_safe_load_marshal Integer 122") { assert_safe_load_marshal "\x04\bi\x7F" } + define_method("test_safe_load_marshal Integer 123") { assert_safe_load_marshal "\x04\bi\x01{" } + define_method("test_safe_load_marshal Integer 124") { assert_safe_load_marshal "\x04\bi\x01|" } + define_method("test_safe_load_marshal Integer 125") { assert_safe_load_marshal "\x04\bi\x01}" } + define_method("test_safe_load_marshal Integer 126") { assert_safe_load_marshal "\x04\bi\x01~" } + define_method("test_safe_load_marshal Integer 127") { assert_safe_load_marshal "\x04\bi\x01\x7F" } + define_method("test_safe_load_marshal Integer 128") { assert_safe_load_marshal "\x04\bi\x01\x80" } + define_method("test_safe_load_marshal Integer 129") { assert_safe_load_marshal "\x04\bi\x01\x81" } + define_method("test_safe_load_marshal Integer 2") { assert_safe_load_marshal "\x04\bi\a" } + define_method("test_safe_load_marshal Integer 254") { assert_safe_load_marshal "\x04\bi\x01\xFE" } + define_method("test_safe_load_marshal Integer 255") { assert_safe_load_marshal "\x04\bi\x01\xFF" } + define_method("test_safe_load_marshal Integer 256") { assert_safe_load_marshal "\x04\bi\x02\x00\x01" } + define_method("test_safe_load_marshal Integer 257") { assert_safe_load_marshal "\x04\bi\x02\x01\x01" } + define_method("test_safe_load_marshal Integer 258") { assert_safe_load_marshal "\x04\bi\x02\x02\x01" } + define_method("test_safe_load_marshal Integer 268435454") { assert_safe_load_marshal "\x04\bi\x04\xFE\xFF\xFF\x0F" } + define_method("test_safe_load_marshal Integer 268435455") { assert_safe_load_marshal "\x04\bi\x04\xFF\xFF\xFF\x0F" } + define_method("test_safe_load_marshal Integer 268435456") { assert_safe_load_marshal "\x04\bi\x04\x00\x00\x00\x10" } + define_method("test_safe_load_marshal Integer 268435457") { assert_safe_load_marshal "\x04\bi\x04\x01\x00\x00\x10" } + define_method("test_safe_load_marshal Integer 3") { assert_safe_load_marshal "\x04\bi\b" } + define_method("test_safe_load_marshal Integer 4") { assert_safe_load_marshal "\x04\bi\t" } + define_method("test_safe_load_marshal Integer 4294967294") { assert_safe_load_marshal "\x04\bl+\a\xFE\xFF\xFF\xFF" } + define_method("test_safe_load_marshal Integer 4294967295") { assert_safe_load_marshal "\x04\bl+\a\xFF\xFF\xFF\xFF" } + define_method("test_safe_load_marshal Integer 4294967296") { assert_safe_load_marshal "\x04\bl+\b\x00\x00\x00\x00\x01\x00" } + define_method("test_safe_load_marshal Integer 4294967297") { assert_safe_load_marshal "\x04\bl+\b\x01\x00\x00\x00\x01\x00" } + define_method("test_safe_load_marshal Integer 5") { assert_safe_load_marshal "\x04\bi\n" } + define_method("test_safe_load_marshal Integer 6") { assert_safe_load_marshal "\x04\bi\v" } + define_method("test_safe_load_marshal Integer 65534") { assert_safe_load_marshal "\x04\bi\x02\xFE\xFF" } + define_method("test_safe_load_marshal Integer 65535") { assert_safe_load_marshal "\x04\bi\x02\xFF\xFF" } + define_method("test_safe_load_marshal Integer 65536") { assert_safe_load_marshal "\x04\bi\x03\x00\x00\x01" } + define_method("test_safe_load_marshal Integer 65537") { assert_safe_load_marshal "\x04\bi\x03\x01\x00\x01" } + define_method("test_safe_load_marshal Integer 7") { assert_safe_load_marshal "\x04\bi\f" } + define_method("test_safe_load_marshal Integer 9223372036854775806") { assert_safe_load_marshal "\x04\bl+\t\xFE\xFF\xFF\xFF\xFF\xFF\xFF\x7F" } + define_method("test_safe_load_marshal Integer 9223372036854775807") { assert_safe_load_marshal "\x04\bl+\t\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x7F" } + define_method("test_safe_load_marshal Integer 9223372036854775808") { assert_safe_load_marshal "\x04\bl+\t\x00\x00\x00\x00\x00\x00\x00\x80" } + define_method("test_safe_load_marshal Integer 9223372036854775809") { assert_safe_load_marshal "\x04\bl+\t\x01\x00\x00\x00\x00\x00\x00\x80" } + define_method("test_safe_load_marshal Rational (1/3)") { assert_safe_load_marshal "\x04\bU:\rRational[\ai\x06i\b" } + define_method("test_safe_load_marshal Array [[...]]") { assert_safe_load_marshal "\x04\b[\x06@\x00" } + define_method("test_safe_load_marshal String \"hello\" ivar") { assert_safe_load_marshal "\x04\bI\"\nhello\a:\x06ET:\n@type@\x00", additional_methods: [:instance_variables], permitted_ivars: { "String" => %w[@type E] } } + define_method("test_safe_load_marshal Array [\"hello\", [\"hello\"], \"hello\", [\"hello\"]]") { assert_safe_load_marshal "\x04\b[\tI\"\nhello\x06:\x06ET[\x06@\x06@\x06@\a" } + define_method("test_safe_load_marshal Array [\"hello\", \"hello\"]") { assert_safe_load_marshal "\x04\b[\aI\"\nhello\x06:\x06ET@\x06" } + define_method("test_safe_load_marshal Array [:development, :development]") { assert_safe_load_marshal "\x04\b[\a:\x10development;\x00" } + define_method("test_safe_load_marshal String \"abc\" ascii") { assert_safe_load_marshal "\x04\bI\"\babc\x06:\x06EF", additional_methods: [:encoding] } + define_method("test_safe_load_marshal Array [\"abc\", \"abc\"] ascii") { assert_safe_load_marshal "\x04\b[\aI\"\babc\x06:\x06EF@\x06", additional_methods: [->(x) { x.map(&:encoding) }] } + define_method("test_safe_load_marshal String \"abc\" utf8") { assert_safe_load_marshal "\x04\bI\"\babc\x06:\x06ET", additional_methods: [:encoding] } + define_method("test_safe_load_marshal Array [\"abc\", \"abc\"] utf8") { assert_safe_load_marshal "\x04\b[\aI\"\babc\x06:\x06ET@\x06", additional_methods: [->(x) { x.map(&:encoding) }] } + define_method("test_safe_load_marshal String \"abc\" Windows-1256") { assert_safe_load_marshal "\x04\bI\"\babc\x06:\rencoding\"\x11Windows-1256", additional_methods: [:encoding] } + define_method("test_safe_load_marshal Array [\"abc\", \"abc\"] Windows-1256") { assert_safe_load_marshal "\x04\b[\aI\"\babc\x06:\rencoding\"\x11Windows-1256@\x06", additional_methods: [->(x) { x.map(&:encoding) }] } + define_method("test_safe_load_marshal String \"abc\" binary") { assert_safe_load_marshal "\x04\b\"\babc", additional_methods: [:encoding] } + define_method("test_safe_load_marshal Array [\"abc\", \"abc\"] binary") { assert_safe_load_marshal "\x04\b[\a\"\babc@\x06", additional_methods: [->(x) { x.map(&:encoding) }] } + define_method("test_safe_load_marshal String \"\\x61\\x62\\x63\" utf32") { assert_safe_load_marshal "\x04\bI\"\babc\x06:\rencoding\"\vUTF-32", additional_methods: [:encoding] } + define_method("test_safe_load_marshal Array [\"\\x61\\x62\\x63\", \"\\x61\\x62\\x63\"] utf32") { assert_safe_load_marshal "\x04\b[\aI\"\babc\x06:\rencoding\"\vUTF-32@\x06", additional_methods: [->(x) { x.map(&:encoding) }] } + define_method("test_safe_load_marshal String \"abc\" ivar") { assert_safe_load_marshal "\x04\bI\"\babc\a:\x06ET:\n@typeI\"\ttype\x06;\x00T", permitted_ivars: { "String" => %w[@type E] } } + define_method("test_safe_load_marshal String \"\"") { assert_safe_load_marshal "\x04\bI\"\babc\x06:\x06ET" } + define_method("test_safe_load_marshal Time 2000-12-31 20:07:59 -1152") { assert_safe_load_marshal "\x04\bIu:\tTime\r'@\x19\x80\x00\x00\xB0\xEF\a:\voffseti\xFE Y:\tzone0", additional_methods: [:ctime, :to_f, :to_r, :to_i, :zone, :subsec, :instance_variables, :dst?, :to_a] } + define_method("test_safe_load_marshal Time 2000-12-31 23:59:59 -0800") { assert_safe_load_marshal "\x04\bIu:\tTime\r'@\x19\x80\x00\x00\xB0\xEF\a:\voffseti\xFE\x80\x8F:\tzoneI\"\bPST\x06:\x06EF", additional_methods: [:ctime, :to_f, :to_r, :to_i, :zone, :subsec, :instance_variables, :dst?, :to_a] } + define_method("test_safe_load_marshal Time 2000-12-31 23:59:59 2254051613498933/2251799813685248000000000 -0800") { assert_safe_load_marshal "\x04\bIu:\tTime\r'@\x19\x80\x00\x00\xB0\xEF\n:\rnano_numl+\t5^\xBAI\f\x02\b\x00:\rnano_denl+\t\x00\x00\x00\x00\x00\x00\b\x00:\rsubmicro\"\a\x00\x10:\voffseti\xFE\x80\x8F:\tzoneI\"\bPST\x06:\x06EF", additional_methods: [:ctime, :to_f, :to_r, :to_i, :zone, :subsec, :instance_variables, :dst?, :to_a] } + define_method("test_safe_load_marshal Time 2000-12-31 23:59:59 2476979795053773/2251799813685248000 -0800") { assert_safe_load_marshal "\x04\bIu:\tTime\r'@\x19\x80L\x04\xB0\xEF\t:\rnano_numi\x025\f:\rnano_denl+\b\x00\x00\x00\x00\x00 :\voffseti\xFE\x80\x8F:\tzoneI\"\bPST\x06:\x06EF", additional_methods: [:ctime, :to_f, :to_r, :to_i, :zone, :subsec, :instance_variables, :dst?, :to_a] } + define_method("test_safe_load_marshal Time 2000-12-31 23:59:59 2476979795053773/2251799813685248000000 -0800") { assert_safe_load_marshal "\x04\bIu:\tTime\r'@\x19\x80\x01\x00\xB0\xEF\n:\rnano_numl+\t\x19\x00\x00\x00\x00\x00d\x00:\rnano_denl+\t\x00\x00\x00\x00\x00\x00\x01\x00:\rsubmicro\"\x06\x10:\voffseti\xFE\x80\x8F:\tzoneI\"\bPST\x06:\x06EF", additional_methods: [:ctime, :to_f, :to_r, :to_i, :zone, :subsec, :instance_variables, :dst?, :to_a] } + define_method("test_safe_load_marshal Time 2000-12-31 23:59:59 2476979795053773/2251799813685248000000000 -0800") { assert_safe_load_marshal "\x04\bIu:\tTime\r'@\x19\x80\x00\x00\xB0\xEF\n:\rnano_numl+\t\xCD\xCC\xCC\xCC\xCC\xCC\b\x00:\rnano_denl+\t\x00\x00\x00\x00\x00\x00\b\x00:\rsubmicro\"\a\x00\x10:\voffseti\xFE\x80\x8F:\tzoneI\"\bPST\x06:\x06EF", additional_methods: [:ctime, :to_f, :to_r, :to_i, :zone, :subsec, :instance_variables, :dst?, :to_a] } + define_method("test_safe_load_marshal Time 2000-12-31 23:59:59 450364466336677/450359962737049600000000 -0800") { assert_safe_load_marshal "\x04\bIu:\tTime\r'@\x19\x80\x00\x00\xB0\xEF\n:\rnano_numl+\t9b->\x05\x00\b\x00:\rnano_denl+\t\x00\x00\x00\x00\x00\x00\b\x00:\rsubmicro\"\a\x00\x10:\voffseti\xFE\x80\x8F:\tzoneI\"\bPST\x06:\x06EF", additional_methods: [:ctime, :to_f, :to_r, :to_i, :zone, :subsec, :instance_variables, :dst?, :to_a] } + define_method("test_safe_load_marshal Time 2000-12-31 23:59:59 4548635623644201/4503599627370496000 -0800") { assert_safe_load_marshal "\x04\bIu:\tTime\r'@\x19\x80\xF2\x03\xB0\xEF\t:\rnano_numi\x02q\x02:\rnano_denl+\b\x00\x00\x00\x00\x00@:\voffseti\xFE\x80\x8F:\tzoneI\"\bPST\x06:\x06EF", additional_methods: [:ctime, :to_f, :to_r, :to_i, :zone, :subsec, :instance_variables, :dst?, :to_a] } + define_method("test_safe_load_marshal Time 2000-12-31 23:59:59 4548635623644201/4503599627370496000000 -0800") { assert_safe_load_marshal "\x04\bIu:\tTime\r'@\x19\x80\x01\x00\xB0\xEF\n:\rnano_numl+\t\x05\x00\x00\x00\x00\x00\x14\x00:\rnano_denl+\t\x00\x00\x00\x00\x00\x00\x02\x00:\rsubmicro\"\x06\x01:\voffseti\xFE\x80\x8F:\tzoneI\"\bPST\x06:\x06EF", additional_methods: [:ctime, :to_f, :to_r, :to_i, :zone, :subsec, :instance_variables, :dst?, :to_a] } + define_method("test_safe_load_marshal Time 2000-12-31 23:59:59 4548635623644201/4503599627370496000000000 -0800") { assert_safe_load_marshal "\x04\bIu:\tTime\r'@\x19\x80\x00\x00\xB0\xEF\n:\rnano_numl+\t)\\\x8F\xC2\xF5(\x10\x00:\rnano_denl+\t\x00\x00\x00\x00\x00\x00\x10\x00:\rsubmicro\"\a\x00\x10:\voffseti\xFE\x80\x8F:\tzoneI\"\bPST\x06:\x06EF", additional_methods: [:ctime, :to_f, :to_r, :to_i, :zone, :subsec, :instance_variables, :dst?, :to_a] } + define_method("test_safe_load_marshal Time 2000-12-31 23:59:59.000000001 -0800") { assert_safe_load_marshal "\x04\bIu:\tTime\r'@\x19\x80\x00\x00\xB0\xEF\n:\rnano_numi\x06:\rnano_deni\x06:\rsubmicro\"\a\x00\x10:\voffseti\xFE\x80\x8F:\tzoneI\"\bPST\x06:\x06EF", additional_methods: [:ctime, :to_f, :to_r, :to_i, :zone, :subsec, :instance_variables, :dst?, :to_a] } + define_method("test_safe_load_marshal Time 2000-12-31 23:59:59.000001 -0800") { assert_safe_load_marshal "\x04\bIu:\tTime\r'@\x19\x80\x01\x00\xB0\xEF\a:\voffseti\xFE\x80\x8F:\tzoneI\"\bPST\x06:\x06EF", additional_methods: [:ctime, :to_f, :to_r, :to_i, :zone, :subsec, :instance_variables, :dst?, :to_a] } + define_method("test_safe_load_marshal Time 2000-12-31 23:59:59.001 -0800") { assert_safe_load_marshal "\x04\bIu:\tTime\r'@\x19\x80\xE8\x03\xB0\xEF\a:\voffseti\xFE\x80\x8F:\tzoneI\"\bPST\x06:\x06EF", additional_methods: [:ctime, :to_f, :to_r, :to_i, :zone, :subsec, :instance_variables, :dst?, :to_a] } + define_method("test_safe_load_marshal Time 2001-01-01 07:59:59 +0000") { assert_safe_load_marshal "\x04\bIu:\tTime\r'@\x19\x80\x00\x00\xB0\xEF\a:\voffseti\x00:\tzone0", additional_methods: [:ctime, :to_f, :to_r, :to_i, :zone, :subsec, :instance_variables, :dst?, :to_a] } + define_method("test_safe_load_marshal Time 2001-01-01 07:59:59 UTC") { assert_safe_load_marshal "\x04\bIu:\tTime\r'@\x19\xC0\x00\x00\xB0\xEF\x06:\tzoneI\"\bUTC\x06:\x06EF", additional_methods: [:ctime, :to_f, :to_r, :to_i, :zone, :subsec, :instance_variables, :dst?, :to_a] } + define_method("test_safe_load_marshal Time 2001-01-01 11:59:59 +0400") { assert_safe_load_marshal "\x04\bIu:\tTime\r'@\x19\x80\x00\x00\xB0\xEF\a:\voffseti\x02@8:\tzone0", additional_methods: [:ctime, :to_f, :to_r, :to_i, :zone, :subsec, :instance_variables, :dst?, :to_a] } + define_method("test_safe_load_marshal Time 2023-08-24 10:10:39.09565 -0700") { assert_safe_load_marshal "\x04\bIu:\tTime\r\x11\xDF\x1E\x80\xA2uq*\a:\voffseti\xFE\x90\x9D:\tzoneI\"\bPDT\x06:\x06EF" } + define_method("test_safe_load_marshal Time 2023-08-24 10:10:39.098453 -0700") { assert_safe_load_marshal "\x04\bIu:\tTime\r\x11\xDF\x1E\x80\x95\x80q*\b:\n@typeI\"\fruntime\x06:\x06ET:\voffseti\xFE\x90\x9D:\tzoneI\"\bPDT\x06;\aF", permitted_ivars: { "Time" => %w[@type offset zone], "String" => %w[E @debug_created_info] }, marshal_dump_equality: (RUBY_ENGINE != "truffleruby" || RUBY_ENGINE_VERSION >= "23") } + def test_repeated_symbol assert_safe_load_as [:development, :development] end @@ -60,7 +174,7 @@ class TestGemSafeMarshal < Gem::TestCase pend "Marshal.load of Time with ivars is broken on jruby, see https://github.com/jruby/jruby/issues/7902" if RUBY_ENGINE == "jruby" with_const(Gem::SafeMarshal, :PERMITTED_IVARS, { "Time" => %w[@type offset zone nano_num nano_den submicro], "String" => %w[E @debug_created_info] }) do - assert_safe_load_as Time.new.tap {|t| t.instance_variable_set :@type, "runtime" } + assert_safe_load_as Time.new.tap {|t| t.instance_variable_set :@type, "runtime" }, marshal_dump_equality: (RUBY_ENGINE != "truffleruby" || RUBY_ENGINE_VERSION >= "23") end end @@ -168,19 +282,24 @@ class TestGemSafeMarshal < Gem::TestCase assert_equal e.message, "Attempting to load unpermitted symbol \"rspec\" @ root.[9].[0].@name" end - def assert_safe_load_as(x, additional_methods: []) - dumped = Marshal.dump(x) + def assert_safe_load_marshal(dumped, additional_methods: [], permitted_ivars: nil, equality: true, marshal_dump_equality: true) loaded = Marshal.load(dumped) - safe_loaded = Gem::SafeMarshal.safe_load(dumped) + safe_loaded = + if permitted_ivars + with_const(Gem::SafeMarshal, :PERMITTED_IVARS, permitted_ivars) do + Gem::SafeMarshal.safe_load(dumped) + end + else + Gem::SafeMarshal.safe_load(dumped) + end # NaN != NaN, for example - if x == x # rubocop:disable Lint/BinaryOperatorWithIdenticalOperands - assert_equal x, safe_loaded, "should load #{dumped.inspect}" + if equality assert_equal loaded, safe_loaded, "should equal what Marshal.load returns" end - 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" + assert_equal loaded.to_s, safe_loaded.to_s, "should have equal to_s" + assert_equal loaded.inspect, safe_loaded.inspect, "should have equal inspect" additional_methods.each do |m| if m.is_a?(Proc) call = m @@ -190,7 +309,15 @@ class TestGemSafeMarshal < Gem::TestCase 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" + if marshal_dump_equality + assert_equal Marshal.dump(loaded).dump, Marshal.dump(safe_loaded).dump, "should Marshal.dump the same" + end + end + + def assert_safe_load_as(x, **kwargs) + dumped = Marshal.dump(x) + equality = x == x # rubocop:disable Lint/BinaryOperatorWithIdenticalOperands + assert_safe_load_marshal(dumped, equality: equality, **kwargs) end def with_const(mod, name, new_value, &block) |