[Python-Dev] Evil reference cycles caused Exception.__traceback__

Victor Stinner victor.stinner at gmail.com
Mon Sep 18 06:02:03 EDT 2017


Hum, my email is long. Maybe an short example is simpler to understand:
---
import gc

class VerboseDestructor:
    # Imagine an object using many limited resources like memory,
    # sockets and/or files
    def __del__(self):
        print("VerboseDestructor")

def create_ref_cycle():
    obj = VerboseDestructor()
    # Create a reference cycle using an exception
    # to keep the frame alive
    try:
        raise ValueError
    except ValueError as exc:
        err = exc

print("create_ref_cycle")
create_ref_cycle()
print("gc.collect")
gc.collect()
print("exit")
---

Output:
---
create_ref_cycle
gc.collect
VerboseDestructor
exit
---

create_ref_cycle() function creates a reference cycle causing the
"obj" variable to be kept alive after create_ref_cycle() exit.

Let's say that the "leaked" object uses a lot of memory. The bug can
now be called a memory leak.

Let's say that the leaked object uses a file. Now the risk is that the
file cannot be removed anymore on Windows (you cannot remove an open
file), or that data is not properly flushed on disk, or that the same
file is re-opened by a different function in a different thread and so
you might corrupt data, etc.

It's not hard to imagine many various issues caused by an object kept
alive longer than expected.

Well, you *can* modify your code to add a VerboseDestructor.close()
method and explicitly releases resources as soon as possible in
create_ref_cycle(). Maybe by adding support for the context manager
protocol to VerboseDestructor and use "with obj:" in
create_ref_cycle().

But here you expect that you are already aware of the reference cycle.

Moreover, Python 3 haters can complain that the code worked perfectly
fine in Python 2...

Victor


More information about the Python-Dev mailing list