[issue38006] Crash in remove() weak reference callback of weakref.WeakValueDictionary at Python exit

Tim Peters report at bugs.python.org
Sat Sep 28 22:49:18 EDT 2019


Tim Peters <tim at python.org> added the comment:

> call_func and remove are part of a reference cycle. A forced garbage
> collection breaks the cycle and removes the two objects, but they are
> not removed in the expected order:
>
> * first: call_func
> * then: remove
>
> The crash requires to destroy the objects in the reverse order

Victor, I'm not sure what you had in mind there, so please flesh it out if the following isn't clear?

In any case "like" the one you constructed, __del__  will always run first, with everything needed wholly intact.

Because tp_clear can leave an object in a useless (or worse) state, gc runs all finalizers and all weakref callbacks before tp_clear is run on anything.  tp_clear is used only in delete_garbage, which is the last non-trivial thing gc does.  Before then, clears and deallocations happen only as side effects of refcounting semantics while running finalizers and callbacks.  So refcount precedence order is respected, and nothing will get torn down before its refcount hits 0.

At the time gc first calls tp_clear, the intent is that no non-trivial code will run again - just tp_clear implementations applying Py_CLEAR to objects' members, and deallocations happening as refcounts fall to 0.  No finalizers, no callbacks, none, ever ;-)

So what I saw your program doing wasn't just an accident relying on the order the objects happened to appear in the list.  Regardless of that order, gc forces __del__ to run before tp_clear is applied to anything, and the call_func instance is wholly intact when its __del__ runs.

----------

_______________________________________
Python tracker <report at bugs.python.org>
<https://bugs.python.org/issue38006>
_______________________________________


More information about the Python-bugs-list mailing list