From 3de3034f9a4e8945119d688fa4399d737f6652d8 Mon Sep 17 00:00:00 2001 From: Herwin Date: Fri, 13 Dec 2024 14:11:10 +0100 Subject: [PATCH] Fix Marshal.dump for String/Regexp with instance variables --- spec/core/marshal/dump_spec.rb | 8 ++------ spec/core/marshal/shared/load.rb | 2 +- src/marshal.rb | 18 ++++++++++-------- 3 files changed, 13 insertions(+), 15 deletions(-) diff --git a/spec/core/marshal/dump_spec.rb b/spec/core/marshal/dump_spec.rb index 19082f7c2a..e55aa5db95 100644 --- a/spec/core/marshal/dump_spec.rb +++ b/spec/core/marshal/dump_spec.rb @@ -358,9 +358,7 @@ def _dump(level) it "dumps a String with instance variables" do str = +"" str.instance_variable_set("@foo", "bar") - NATFIXME 'dumps a String with instance variables', exception: SpecFailedException do - Marshal.dump(str.force_encoding("binary")).should == "\x04\bI\"\x00\x06:\t@foo\"\bbar" - end + Marshal.dump(str.force_encoding("binary")).should == "\x04\bI\"\x00\x06:\t@foo\"\bbar" end it "dumps a US-ASCII String" do @@ -400,9 +398,7 @@ def _dump(level) it "dumps a Regexp with instance variables" do o = Regexp.new("") o.instance_variable_set(:@ivar, :ivar) - NATFIXME 'dumps a Regexp with instance variables', exception: SpecFailedException do - Marshal.dump(o).should == "\x04\bI/\x00\x00\a:\x06EF:\n@ivar:\tivar" - end + Marshal.dump(o).should == "\x04\bI/\x00\x00\a:\x06EF:\n@ivar:\tivar" end it "dumps an extended Regexp" do diff --git a/spec/core/marshal/shared/load.rb b/spec/core/marshal/shared/load.rb index 5492998eeb..e8353a2fcb 100644 --- a/spec/core/marshal/shared/load.rb +++ b/spec/core/marshal/shared/load.rb @@ -613,7 +613,7 @@ h = { key: s } h.instance_variable_set :@hash_ivar, 'hash ivar' - NATFIXME 'preserves hash ivars when hash contains a string having ivar', exception: SpecFailedException do + NATFIXME 'issue with additional @ in ivar name', exception: NameError do unmarshalled = Marshal.send(@method, Marshal.dump(h)) unmarshalled.instance_variable_get(:@hash_ivar).should == 'hash ivar' unmarshalled[:key].instance_variable_get(:@string_ivar).should == 'string ivar' diff --git a/src/marshal.rb b/src/marshal.rb index 97084b4a00..48d8ffefb6 100644 --- a/src/marshal.rb +++ b/src/marshal.rb @@ -102,15 +102,17 @@ def write_string_bytes(value) end def write_encoding_bytes(value) + ivars = value.instance_variables.map { |ivar_name| [ivar_name, value.instance_variable_get(ivar_name)] } case value.encoding when Encoding::US_ASCII - write_integer_bytes(1) - write_symbol(:E) - write_false + ivars.prepend([:E, false]) when Encoding::UTF_8 - write_integer_bytes(1) - write_symbol(:E) - write_true + ivars.prepend([:E, true]) + end + write_integer_bytes(ivars.size) unless ivars.empty? + ivars.each do |ivar_name, ivar_value| + write(ivar_name) + write(ivar_value) end end @@ -141,10 +143,10 @@ def write_integer(value) end def write_string(value) - write_char('I') if value.encoding != Encoding::ASCII_8BIT + write_char('I') if value.encoding != Encoding::ASCII_8BIT || !value.instance_variables.empty? write_char('"') write_string_bytes(value) - write_encoding_bytes(value) if value.encoding != Encoding::ASCII_8BIT + write_encoding_bytes(value) end def write_symbol(value)