psych icon indicating copy to clipboard operation
psych copied to clipboard

psych fails to load YAML containing serialized objects for which `klass.allocate` returns nil

Open rick opened this issue 10 years ago • 2 comments

The beaker testing library serializes a YAML file representing the configuration for a prior test run. That library can contain AWS::Core::Data objects (see http://docs.aws.amazon.com/AWSRubySDK/latest/AWS/Core/Data.html).

For example, a snippet might look like:

        :placement: !ruby/object:AWS::Core::Data
          data:
            :availability_zone: us-west-2a
            :group_name:
            :tenancy: default

The problem is that AWS::Core::Data somehow manages to have its .allocate method return nil:

>> require 'aws/core/data'
=> true
>> AWS::Core::Data.allocate
=> nil

When this is de-serialized, s here becomes nil: https://github.com/tenderlove/psych/blob/master/lib/psych/visitors/to_ruby.rb#L371 and then fireworks happen here: https://github.com/tenderlove/psych/blob/master/lib/psych/visitors/to_ruby.rb#L379

The end of the stack trace looks like:

/home/rick/pl/pe_acceptance_tests/vendor/ruby/gems/aws-sdk-v1-1.65.0/lib/aws/core/data.rb:146:in `respond_to?': undefined method `key?' for nil:NilClass (NoMethodError)
    from /home/rick/pl/pe_acceptance_tests/vendor/ruby/gems/psych-2.0.15/lib/psych/visitors/to_ruby.rb:379:in `init_with'
    from /home/rick/pl/pe_acceptance_tests/vendor/ruby/gems/psych-2.0.15/lib/psych/visitors/to_ruby.rb:372:in `revive'
    from /home/rick/pl/pe_acceptance_tests/vendor/ruby/gems/psych-2.0.15/lib/psych/visitors/to_ruby.rb:207:in `visit_Psych_Nodes_Mapping'
    from /home/rick/pl/pe_acceptance_tests/vendor/ruby/gems/psych-2.0.15/lib/psych/visitors/visitor.rb:15:in `visit'
    from /home/rick/pl/pe_acceptance_tests/vendor/ruby/gems/psych-2.0.15/lib/psych/visitors/visitor.rb:5:in `accept'
    from /home/rick/pl/pe_acceptance_tests/vendor/ruby/gems/psych-2.0.15/lib/psych/visitors/to_ruby.rb:31:in `accept'
    from /home/rick/pl/pe_acceptance_tests/vendor/ruby/gems/psych-2.0.15/lib/psych/visitors/to_ruby.rb:336:in `block in revive_hash'

I don't think AWS::Core::Data is being a good ruby citizen by doing whatever they're doing with .allocate; but perhaps the error thrown here good be more intuitive. We may work around this with a to_yaml at serialization time (or something similar), but figured this was worth reporting.

rick avatar Sep 02 '15 21:09 rick

Wow. Yes, this doesn't seem like a good thing. We could probably unbind the real allocate method and bind it to that object. I'll try to think of something.

Thanks for reporting this!

Aaron Patterson http://tenderlovemaking.com/ I'm on an iPhone so I apologize for top posting.

On Sep 2, 2015, at 11:18 PM, Rick Bradley [email protected] wrote:

The beaker testing library serializes a YAML file representing the configuration for a prior test run. That library can contain AWS::Core::Data objects (see http://docs.aws.amazon.com/AWSRubySDK/latest/AWS/Core/Data.html).

For example, a snippet might look like:

    :placement: !ruby/object:AWS::Core::Data
      data:
        :availability_zone: us-west-2a
        :group_name:
        :tenancy: default

The problem is that AWS::Core::Data somehow manages to have its .allocate method return nil:

require 'aws/core/data' => true AWS::Core::Data.allocate => nil When this is de-serialized, s here becomes nil: https://github.com/tenderlove/psych/blob/master/lib/psych/visitors/to_ruby.rb#L371 and then fireworks happen here: https://github.com/tenderlove/psych/blob/master/lib/psych/visitors/to_ruby.rb#L379

The end of the stack trace looks like:

/home/rick/pl/pe_acceptance_tests/vendor/ruby/gems/aws-sdk-v1-1.65.0/lib/aws/core/data.rb:146:in respond_to?': undefined methodkey?' for nil:NilClass (NoMethodError) from /home/rick/pl/pe_acceptance_tests/vendor/ruby/gems/psych-2.0.15/lib/psych/visitors/to_ruby.rb:379:in init_with' from /home/rick/pl/pe_acceptance_tests/vendor/ruby/gems/psych-2.0.15/lib/psych/visitors/to_ruby.rb:372:inrevive' from /home/rick/pl/pe_acceptance_tests/vendor/ruby/gems/psych-2.0.15/lib/psych/visitors/to_ruby.rb:207:in visit_Psych_Nodes_Mapping' from /home/rick/pl/pe_acceptance_tests/vendor/ruby/gems/psych-2.0.15/lib/psych/visitors/visitor.rb:15:invisit' from /home/rick/pl/pe_acceptance_tests/vendor/ruby/gems/psych-2.0.15/lib/psych/visitors/visitor.rb:5:in accept' from /home/rick/pl/pe_acceptance_tests/vendor/ruby/gems/psych-2.0.15/lib/psych/visitors/to_ruby.rb:31:inaccept' from /home/rick/pl/pe_acceptance_tests/vendor/ruby/gems/psych-2.0.15/lib/psych/visitors/to_ruby.rb:336:in `block in revive_hash' I don't think AWS::Core::Data is being a good ruby citizen by doing whatever they're doing with .allocate; but perhaps the error thrown here good be more intuitive. We may work around this with a to_yaml at serialization time (or something similar), but figured this was worth reporting.

― Reply to this email directly or view it on GitHub.

tenderlove avatar Sep 03 '15 05:09 tenderlove

Scrolling through the issues, I hit this. I really cannot see how this is Psych's concern. Class.new calls klass.allocate.initialize. If klass.allocate returns nil, then many, many things are expected to break. For some library to know what another library or application intends that instead resulted in this nil is simply not possible. If you want to use Psych to deserialize such an object, you will have to provide the necessary code to handle the matter.

NathanZook avatar Apr 26 '21 22:04 NathanZook