Skip to content

Commit

Permalink
LoopTest : Demonstrate deadlock due to hash aliasing
Browse files Browse the repository at this point in the history
Although this is contrived, it demonstrates an important point : hashes can alias on the _same_ plug, just in different contexts.
  • Loading branch information
johnhaddon committed Oct 9, 2023
1 parent 531c91d commit 5f87394
Showing 1 changed file with 25 additions and 0 deletions.
25 changes: 25 additions & 0 deletions python/GafferTest/LoopTest.py
Original file line number Diff line number Diff line change
Expand Up @@ -282,5 +282,30 @@ def plugDirtied( plug ) :
for plug, value in valuesWhenDirtied.items() :
self.assertEqual( plugValue( plug ), value )

@GafferTest.TestRunner.CategorisedTestMethod( { "taskCollaboration:hashAliasing" } )
def testHashAliasingDeadlock( self ) :

script = Gaffer.ScriptNode()

script["loop"] = Gaffer.Loop()
script["loop"].setup( Gaffer.StringPlug() )

# Dumb expression that just sets the value for the next iteration to
# the value from the previous iteration. Because of de8ab79d6f958cef3b80954798f8083a346945a7,
# the hash for the expression output is identical for every iteration of
# the loop, even though the context differs.
script["expression"] = Gaffer.Expression()
script["expression"].setExpression( """parent["loop"]["next"] = parent["loop"]["previous"]""" )

# Get the result of the loop. This actually computes the _first_ iteration of the loop first,
# while computing the hash of the result, and reuses the result for every other loop iteration.
script["loop"]["out"].getValue()
# Simulate cache eviction by clearing the compute cache.
Gaffer.ValuePlug.clearCache()
# Get the value again. Now, because the hash is still cached, this will first start the
# compute for the _last_ iteration. This leads to a recursive compute, which can cause deadlock
# if not handled appropriately.
script["loop"]["out"].getValue()

if __name__ == "__main__":
unittest.main()

0 comments on commit 5f87394

Please sign in to comment.