lua-users home
lua-l archive

[Date Prev][Date Next][Thread Prev][Thread Next] [Date Index] [Thread Index]

I believe I just worked through a bug in my project caused by weak caches together with userdata finalization, but I wanted to confirm that my analysis was correct and not just the result of sleep deprivation.

* Lua 5.1.4
* Two userdatas each with __gc metamethods. Let's call them UD1 and UD2.
* We also have a table T.
* T references UD2 -- e.g., T.x == UD2
* T is accessible in a weak cache C (getmetatable( C ).__mode == 'kv') and C[ 'key' ] == T
* UD1 has an environment that also references T -- e.g., getfenv( UD1 ).y == T

So, here is what I think is happening to me that I want to confirm is possible.

* The GC finds that neither UD1 nor UD2 (nor T) are accessible via strong links, so it queues UD1 and UD2 for finalization.
* As part of queueing UD1 for finalization, it marks its environment so that that remains available for the __gc metamethod and this in turn marks T.
* T then survives in the cache.
* We fetch T out of the cache.
* This doesn't stop UD2 from being finalized which then makes us unhappy when we go to use use UD2 via T.x.

Except that writing this down, it doesn't jive with my recollection of what the GC does. In particular, I would have expected the reference to T in C to have been cleared even if T is kept alive by the finalization logic.

The symptom, however, is clearly that we go to use UD2 and it has already been finalized. UD1, on the other hand, was just a theory.

Any other insights into how we could end up running through weak caches and reaching an object that has been or will be finalized? I know about the dangers with keys on weak tables since those are identified as potentially being needed by the __gc metamethod, but I am not iterating weak tables anywhere in a way that would discover such finalized keys.