Armin Rigo <[email protected]> added the comment: Ok, figured out why we get this behavior. I think the issue was introduced when we made the Garbage Collector incremental. Here it goes:
1. We have an object x that has both a finalizer (a __del__ method) and a weakref to it. 2. At the end of the MARKING state of collection, we figure out that x has no more references, so we enqueue "call the finalizer" and resurrect x so that it is still usable in the finalizer. As a result, x is resurrected, and we do NOT free the link from the weakref to x yet. 3. Now, at a _later_ step of the same collection, we actually call the RPython-level finalizer, which invalidates the weakref as the first step. But the Python program might have done anything between steps 2 and 3, like fetching a strong reference to x via the weakref. So at step 3 we will incorrectly invalidate a weakref that might have strong references around. We will also incorrectly call the __del__() method on the object even with strong references around. Note that we need to be careful when fixing this, because CPython rules that weakrefs are cleared before the __del__() method is called --- even though of course there is still a reference to the object, as we're going to call a method on it. Likely, the fix should be along the lines of: in the step 2 above, we should still free the links from the weakref to x, IF we schedule x's finalizer to be called; but we should NOT free the links from other weakrefs to other objects IF we don't schedule their finalizers to be called. ---------- nosy: +arigo ________________________________________ PyPy bug tracker <[email protected]> <https://bugs.pypy.org/issue1687> ________________________________________ _______________________________________________ pypy-issue mailing list [email protected] https://mail.python.org/mailman/listinfo/pypy-issue
