#inspect goes into infinite loop #22

Closed
mperham opened this Issue Jan 29, 2012 · 13 comments

Comments

Projects
None yet
8 participants
@mperham
Contributor

mperham commented Jan 29, 2012

An actor that has an ivar to an object that contains a circular reference to the same actor will go into an infinite loop when #inspect is called on the actor.

@benlangfeld

This comment has been minimized.

Show comment
Hide comment
@benlangfeld

benlangfeld Mar 23, 2012

Member

@tarcieri Do you have any thoughts on the way to approach the fix for this? I need to get it fixed within the next few days and would appreciate some pointers.

Member

benlangfeld commented Mar 23, 2012

@tarcieri Do you have any thoughts on the way to approach the fix for this? I need to get it fixed within the next few days and would appreciate some pointers.

@mperham

This comment has been minimized.

Show comment
Hide comment
@mperham

mperham Mar 23, 2012

Contributor

Ben, I worked around this bug in Sidekiq by overriding #inspect.

On 23 Mar 2012, at 00:58, Ben Langfeldreply@reply.github.com wrote:

@tarcieri Do you have any thoughts on the way to approach the fix for this? I need to get it fixed within the next few days and would appreciate some pointers.


Reply to this email directly or view it on GitHub:
#22 (comment)

Contributor

mperham commented Mar 23, 2012

Ben, I worked around this bug in Sidekiq by overriding #inspect.

On 23 Mar 2012, at 00:58, Ben Langfeldreply@reply.github.com wrote:

@tarcieri Do you have any thoughts on the way to approach the fix for this? I need to get it fixed within the next few days and would appreciate some pointers.


Reply to this email directly or view it on GitHub:
#22 (comment)

@tarcieri

This comment has been minimized.

Show comment
Hide comment
@tarcieri

tarcieri Mar 23, 2012

Member

Short of that I don''t have a near-term solution, unfortunately. I need a recursion detection mechanism, and that won't be trivial. I've been mulling some sort of way to collect stack traces across actors. At the very least I need a UUID mechanism for call chains.

Member

tarcieri commented Mar 23, 2012

Short of that I don''t have a near-term solution, unfortunately. I need a recursion detection mechanism, and that won't be trivial. I've been mulling some sort of way to collect stack traces across actors. At the very least I need a UUID mechanism for call chains.

@benlangfeld

This comment has been minimized.

Show comment
Hide comment
@benlangfeld

benlangfeld Mar 23, 2012

Member

I'll try implementing some simple recursion detection over the next
few days to get the ball rolling.

Regards,
Ben Langfeld

Em 23 Mar 2012, às 16:07, Tony Arcieri
reply@reply.github.com
escreveu:

Short of that I don''t have a near-term solution, unfortunately. I need a recursion detection mechanism, and that won't be trivial. I've been mulling some sort of way to collect stack traces across actors.


Reply to this email directly or view it on GitHub:
#22 (comment)

Member

benlangfeld commented Mar 23, 2012

I'll try implementing some simple recursion detection over the next
few days to get the ball rolling.

Regards,
Ben Langfeld

Em 23 Mar 2012, às 16:07, Tony Arcieri
reply@reply.github.com
escreveu:

Short of that I don''t have a near-term solution, unfortunately. I need a recursion detection mechanism, and that won't be trivial. I've been mulling some sort of way to collect stack traces across actors.


Reply to this email directly or view it on GitHub:
#22 (comment)

@tarcieri

This comment has been minimized.

Show comment
Hide comment
@tarcieri

tarcieri Mar 25, 2012

Member

I added Celluloid.uuid that I'd like to be able to use to track "call chains", that is the flow of calls between actors. Each call chain will have a unique UUID.

If you know the UUID of every active call chain, it shouldn't be too hard to detect "recursion", or perhaps more aptly reentrant calls from the same call chain.

Member

tarcieri commented Mar 25, 2012

I added Celluloid.uuid that I'd like to be able to use to track "call chains", that is the flow of calls between actors. Each call chain will have a unique UUID.

If you know the UUID of every active call chain, it shouldn't be too hard to detect "recursion", or perhaps more aptly reentrant calls from the same call chain.

@knewter

This comment has been minimized.

Show comment
Hide comment
@knewter

knewter Apr 24, 2012

Contributor

👍 I'm a total noob and this infinite loop is trivial to run into and caused me moderately sad grief. My load spiked to > 1000 on a core i5 in about 60 seconds

Contributor

knewter commented Apr 24, 2012

👍 I'm a total noob and this infinite loop is trivial to run into and caused me moderately sad grief. My load spiked to > 1000 on a core i5 in about 60 seconds

@tarcieri

This comment has been minimized.

Show comment
Hide comment
@tarcieri

tarcieri Apr 24, 2012

Member

:(

The temporary workaround is to redefine "inspect" on one of the objects.

I have the rudiments of a permanent fix in place, but I have not yet wired them up

Member

tarcieri commented Apr 24, 2012

:(

The temporary workaround is to redefine "inspect" on one of the objects.

I have the rudiments of a permanent fix in place, but I have not yet wired them up

@tarcieri

This comment has been minimized.

Show comment
Hide comment
@tarcieri

tarcieri Dec 12, 2012

Member

In case anyone is wondering, this is still a known issue. I will try to get a fix into Celluloid 0.13

Member

tarcieri commented Dec 12, 2012

In case anyone is wondering, this is still a known issue. I will try to get a fix into Celluloid 0.13

@jrochkind

This comment has been minimized.

Show comment
Hide comment
@jrochkind

jrochkind Jan 30, 2013

Contributor

Ruby stdlib Object#inspect avoids this with some kind of recursion detector. It may (or may not) be useful to look at how it does so as a model. It seems to use a C function 'rb_exec_recursive'. You may be well familiar with this and know exactly what ruby Object#inspect does and why it doesn't apply to celluloid, just didn't see it mentioned and got curious and went to look at the ruby stdlib code and behavior.

1.9.3p194 :001 > o = Object.new
 => #<Object:0x1f9dac> 
1.9.3p194 :002 > o.instance_variable_set("@foo", o)
 => #<Object:0x1f9dac @foo=#<Object:0x1f9dac ...>> 
1.9.3p194 :003 > o.inspect
 => "#<Object:0x1f9dac @foo=#<Object:0x1f9dac ...>>" 
Contributor

jrochkind commented Jan 30, 2013

Ruby stdlib Object#inspect avoids this with some kind of recursion detector. It may (or may not) be useful to look at how it does so as a model. It seems to use a C function 'rb_exec_recursive'. You may be well familiar with this and know exactly what ruby Object#inspect does and why it doesn't apply to celluloid, just didn't see it mentioned and got curious and went to look at the ruby stdlib code and behavior.

1.9.3p194 :001 > o = Object.new
 => #<Object:0x1f9dac> 
1.9.3p194 :002 > o.instance_variable_set("@foo", o)
 => #<Object:0x1f9dac @foo=#<Object:0x1f9dac ...>> 
1.9.3p194 :003 > o.inspect
 => "#<Object:0x1f9dac @foo=#<Object:0x1f9dac ...>>" 
@tarcieri

This comment has been minimized.

Show comment
Hide comment
@tarcieri

tarcieri Jan 30, 2013

Member

@jrochkind yeah, so I've been building the prerequisites for a recursion detector in Celluloid. All call chains are now tagged with a UUID, so in theory it's as simple as walking the task lists and see if another task for the same method name is participating in the same call chain as the current one (i.e. they have the same UUID).

Unfortunately there's not presently a way to inspect the call chain for a given task, although that information is being propagated throughout the system.

Member

tarcieri commented Jan 30, 2013

@jrochkind yeah, so I've been building the prerequisites for a recursion detector in Celluloid. All call chains are now tagged with a UUID, so in theory it's as simple as walking the task lists and see if another task for the same method name is participating in the same call chain as the current one (i.e. they have the same UUID).

Unfortunately there's not presently a way to inspect the call chain for a given task, although that information is being propagated throughout the system.

@chuckremes

This comment has been minimized.

Show comment
Hide comment
@chuckremes

chuckremes Jan 30, 2013

Contributor

What's the recommended work around for now? Is it sufficient to define an #inspect method on actors in the system? Or do I need to redefine inspect on non-actor objects too?

Contributor

chuckremes commented Jan 30, 2013

What's the recommended work around for now? Is it sufficient to define an #inspect method on actors in the system? Or do I need to redefine inspect on non-actor objects too?

@tarcieri

This comment has been minimized.

Show comment
Hide comment
@tarcieri

tarcieri Jan 30, 2013

Member

Redefine #inspect for actors pretty much. You might also confirm you're seeing a spike in CPU usage

Member

tarcieri commented Jan 30, 2013

Redefine #inspect for actors pretty much. You might also confirm you're seeing a spike in CPU usage

tarcieri added a commit that referenced this issue May 12, 2013

Detect recursion in #inspect (fixes #22)
This detects recursion between actors during #inspect and similates Ruby's own
behavior for representing circular object graphs, replacing duplicate instances
of the original actor in the inspect output with "...", e.g.:

    #<Celluloid::ActorProxy(Foo:0x3fe79ea577f4) @bar=#<Celluloid::ActorProxy(
    Bar:0x3fe79e0585b4) @foo=...>>

The above shows a cyclical relationship between the Foo and Bar classes.

Without this sort of detection #inspect goes into an infinite loop which can
be both confusing and infuriating to newcomers and the experienced alike,
myself included!
@halorgium

This comment has been minimized.

Show comment
Hide comment
@halorgium

halorgium May 13, 2013

Member

I'm gonna close this as we have a solution in #250.

Member

halorgium commented May 13, 2013

I'm gonna close this as we have a solution in #250.

@halorgium halorgium closed this May 13, 2013

@benlangfeld benlangfeld referenced this issue in adhearsion/adhearsion Oct 14, 2013

Closed

#inspect infinite loops #377

@benlangfeld benlangfeld referenced this issue in adhearsion/adhearsion Jan 5, 2014

Closed

Infinite loop working with Call variables #416

halorgium added a commit that referenced this issue Nov 29, 2014

Merge pull request #22 from halorgium/evented-mailbox
Depend on Celluloid::EventedMailbox instead of Celluloid::IO::Mailbox

@digitalextremist digitalextremist modified the milestones: 1.0, 0.18.0 Jun 6, 2016

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment