From b8cdb404643afede4cb95fa5e988889e23a0285d Mon Sep 17 00:00:00 2001 From: Herwin Date: Fri, 13 Dec 2024 19:24:07 +0100 Subject: [PATCH] Support Data in Marshal.load/Marshal.restore --- spec/core/marshal/shared/load.rb | 22 +++++++--------------- src/marshal.rb | 20 ++++++++++++++++++++ 2 files changed, 27 insertions(+), 15 deletions(-) diff --git a/spec/core/marshal/shared/load.rb b/spec/core/marshal/shared/load.rb index c8644efe3f..4dd398ea7c 100644 --- a/spec/core/marshal/shared/load.rb +++ b/spec/core/marshal/shared/load.rb @@ -830,20 +830,18 @@ def io.binmode; raise "binmode"; end it "loads a struct having ivar" do obj = Struct.new("Thick").new obj.instance_variable_set(:@foo, 5) - NATFIXME 'loads a struct having ivar', exception: ArgumentError, message: 'dump format error' do + NATFIXME 'ivar names', exception: NameError, message: "`@@foo' is not allowed as an instance variable name" do reloaded = Marshal.send(@method, "\004\bIS:\022Struct::Thick\000\006:\t@fooi\n") reloaded.should == obj reloaded.instance_variable_get(:@foo).should == 5 - Struct.send(:remove_const, :Thick) end + Struct.send(:remove_const, :Thick) end it "loads a struct having fields" do obj = Struct.new("Ure1", :a, :b).new - NATFIXME 'loads a struct having fields', exception: ArgumentError, message: 'dump format error' do - Marshal.send(@method, "\004\bS:\021Struct::Ure1\a:\006a0:\006b0").should == obj - Struct.send(:remove_const, :Ure1) - end + Marshal.send(@method, "\004\bS:\021Struct::Ure1\a:\006a0:\006b0").should == obj + Struct.send(:remove_const, :Ure1) end it "does not call initialize on the unmarshaled struct" do @@ -870,9 +868,7 @@ def io.binmode; raise "binmode"; end dumped = "\x04\bS:#MarshalSpec::DataSpec::Measure\a:\vamountii:\tunit\"\akm" Marshal.dump(obj).should == dumped - NATFIXME 'load Data', exception: ArgumentError, message: 'dump format error' do - Marshal.send(@method, dumped).should == obj - end + Marshal.send(@method, dumped).should == obj end it "loads an extended Data" do @@ -880,9 +876,7 @@ def io.binmode; raise "binmode"; end dumped = "\x04\bS:+MarshalSpec::DataSpec::MeasureExtended\a:\vamountii:\tunit\"\akm" Marshal.dump(obj).should == dumped - NATFIXME 'load Data', exception: ArgumentError, message: 'dump format error' do - Marshal.send(@method, dumped).should == obj - end + Marshal.send(@method, dumped).should == obj end it "returns a frozen object" do @@ -890,9 +884,7 @@ def io.binmode; raise "binmode"; end dumped = "\x04\bS:#MarshalSpec::DataSpec::Measure\a:\vamountii:\tunit\"\akm" Marshal.dump(obj).should == dumped - NATFIXME 'load Data', exception: ArgumentError, message: 'dump format error' do - Marshal.send(@method, dumped).should.frozen? - end + Marshal.send(@method, dumped).should.frozen? end end end diff --git a/src/marshal.rb b/src/marshal.rb index 514f6bca38..c4a346b5c6 100644 --- a/src/marshal.rb +++ b/src/marshal.rb @@ -529,6 +529,24 @@ def read_user_marshaled_object_without_allocate object_class._load(data) end + def read_struct + name = read_value + object_class = find_constant(name) + size = read_integer + values = size.times.each_with_object({}) do |_, tmp| + name = read_value + value = read_value + tmp[name] = value + end + if object_class.ancestors.include?(Data) + object_class.new(**values) + else + object = object_class.allocate + values.each { |k, v| object.send(:"#{k}=", v) } + object + end + end + def read_object name = read_value object_class = find_constant(name) @@ -595,6 +613,8 @@ def read_value read_user_marshaled_object_with_allocate when 'u' read_user_marshaled_object_without_allocate + when 'S' + read_struct when 'o' read_object when 'I'