Author vstinner
Recipients Mark.Shannon, christian.heimes, jdemeyer, lukasz.langa, pablogsal, petr.viktorin, pitrou, vstinner
Date 2019-09-03.12:45:01
SpamBayes Score -1.0
Marked as misclassified Yes
Message-id <1567514701.35.0.255986681549.issue38006@roundup.psfhosted.org>
In-reply-to
Content
Second step: when func_clear() is called, the closure is cleared. Clearing the closure should call the function which is being cleared (or is already cleared).

---
import gc

class CallFunc:
    def __del__(self):
        func = self.func
        if func is None:
            return
        print("CallFunc", func)
        func("call func from CallFunc.__del__")

def create_remove():
    call_func = CallFunc()
    def remove(msg):
        x = call_func
        print(msg)
    remove.__name__ = "evil_func"
    call_func.func = remove
    return call_func, remove

call_func, remove = create_remove()
print("== clear ==")
call_func = None
remove = None
print()

print("== collect ==")
gc.collect()
print()

print("== exit ==")
---

Output (with my hacked CPython):
------------------
== clear ==

== collect ==
CallFunc <function create_remove.<locals>.remove at 0x7fab8a189eb0>
call func from CallFunc.__del__
func_clear remove() -- in delete_garbage? 1

== exit ==
------------------

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
History
Date User Action Args
2019-09-03 12:45:01vstinnersetrecipients: + vstinner, pitrou, christian.heimes, petr.viktorin, lukasz.langa, Mark.Shannon, jdemeyer, pablogsal
2019-09-03 12:45:01vstinnersetmessageid: <1567514701.35.0.255986681549.issue38006@roundup.psfhosted.org>
2019-09-03 12:45:01vstinnerlinkissue38006 messages
2019-09-03 12:45:01vstinnercreate