mozy/ruby-protocol-buffers

Stack Level Too Deep Exception when creating self referenced field type

kb opened this issue · 4 comments

kb commented

I'm running into a Stack Level Too Deep issue when defining a field within itself. Essentially I'm looking into nesting more Baz objects within a Baz object (exert from my generated file below)

class Baz < ::ProtocolBuffers::Message
  optional ::Foo::Bar::Baz, :caused_by, 1

  gen_methods! # new fields ignored after this point
end

However the gem blows up on the self.fields method on the Message class. The calling class is the Decoder from self.decode. Everything goes smoothly until it hits the field definition for Baz within the Baz class and the gem gets stuck referencing self.fields over and over again until it hits a stack level too deep exception.

I currently have this functionality working properly for both Java and C protobufs, so I'm not exactly sure why the ruby version isn't behaving in the same manner.

Any ideas?

Sounds like a pretty clear bug, I don't think anybody has tried to use a recursive message with ruby-protocol-buffers before.

kb commented

I'll dig into this a bit more and see if I can work a fix out for it. Do you have any recommendations as to where I should start looking into a fix for this? I'm just getting into the inner workings of the gem now.

I'm not sure, but I'd guess that maybe the decoder is not being lazy enough -- maybe it's instantiating a sub-object to parse even if the field is blank, throwing things into a loop. If you don't have any luck tracking it down, I might get a chance this weekend to test it out.

kb commented

I believe I've tracked down the issue that causes the looping, which eventually throws the Stack Level Too Deep exception.

Within the else block in the def initialize(attributes = { }) method on the Message class there is a call to field.default_value. This calls the def default_value method on the MessageField class. The MessageField class is initialized with the proxy_class of recursive field, so when default_value is called and executes @proxy_class.new within the def default_value method on the MessageField it calls def initialize(attributes = { }) method on the Message class again. This fun process happens until the exception is thrown.

Any good ideas on resolving this issue?