ostruct icon indicating copy to clipboard operation
ostruct copied to clipboard

Incorrect deserialization of some instances serialized by version 0.2.0

Open aalong-tr opened this issue 2 years ago • 0 comments

In the ruby 2 version of OpenStruct, serialized objects can have two root keys: table and modifiable. The second key only seems to appear after an attribute is assigned post-initialization:

irb(main):012:0> OpenStruct::VERSION
=> "0.2.0"
irb(main):013:0> RUBY_VERSION
=> "2.7.5"
irb(main):014:0> s = OpenStruct.new(foo: 1, bar: 'baz')
=> #<OpenStruct foo=1, bar="baz">
irb(main):015:0> Psych.dump s
=> "--- !ruby/object:OpenStruct\ntable:\n  :foo: 1\n  :bar: baz\n"
irb(main):017:0> s.bar = 'baz'
=> "baz"
irb(main):019:0> Psych.dump s
=> "--- !ruby/object:OpenStruct\ntable:\n  :foo: 1\n  :bar: baz\nmodifiable: true\n"

On newer versions of OpenStruct, serialized objects with that key are not deserialized as expected:

irb(main):010:0> OpenStruct::VERSION
=> "0.3.1"
irb(main):011:0> RUBY_VERSION
=> "3.0.5"
irb(main):012:0> s = Psych.load "--- !ruby/object:OpenStruct\ntable:\n  :foo: 1\n  :bar: baz\nmodifiable: true\n"
=> #<OpenStruct table={:foo=>1, :bar=>"baz"}, modifiable=true>
irb(main):013:0> s.foo
=> nil

The deserialization hook provided by OpenStruct attempts to be backwards compatible, but incorrectly assumes that legacy documents have exactly one root-level key table: https://github.com/ruby/ostruct/blob/master/lib/ostruct.rb#L449-L454

aalong-tr avatar Feb 17 '23 20:02 aalong-tr