classification
Title: refcount gc bug?
Type: Stage:
Components: Versions: Python 2.6, Python 2.5
process
Status: closed Resolution: not a bug
Dependencies: Superseder:
Assigned To: Nosy List: loewis, ocean-city, pitrou
Priority: normal Keywords:

Created on 2008-08-07 10:54 by ocean-city, last changed 2008-08-07 13:43 by pitrou. This issue is now closed.

Messages (7)
msg70816 - (view) Author: Hirokazu Yamamoto (ocean-city) * (Python committer) Date: 2008-08-07 10:54
I'm not sure this is bug or not, but shouldn't `io' be collected by
refcount GC? This happens on python2.5 but doesn't happend on python3.0.

import os

def foo():
    io = open("a.txt", "w")
    raise RuntimeError()

try:
    foo()
except:
    pass

os.remove("a.txt") # WindowsError (Error32)
    # Process cannot access to the file.
    # Another process is using it.
msg70817 - (view) Author: Martin v. Löwis (loewis) * (Python committer) Date: 2008-08-07 11:32
The interpreter holds onto sys.exc_traceback even after the except
block. This refers to the frame, which refers to the file object.
msg70819 - (view) Author: Hirokazu Yamamoto (ocean-city) * (Python committer) Date: 2008-08-07 12:55
Hmm, when exception occurs in some frame, its reference will be
retained even after exiting function? Indeed, extra
exception fixed problem.

import os

def foo():
    io = open("a.txt", "w")
    raise RuntimeError()

try:
    foo()
except:
    pass

try:
    raise RuntimeError()
except:
    pass

os.remove("a.txt") # fine

But still I'm little confused why this code prints "del".

class A:
    def __del__(self):
        print "del"

def foo():
    a = A()
    raise RuntimeError()

try:
    foo()
except:
    pass

I found this behavior when investigating issue3210. When
Lib/subprocess.py (814)'s CreateProcess() raises exception,
p2cread will be freed by refcount GC, it never happen before
os.remove(). And this error is also fixed by same hack.

import subprocess, os

file = open("filename", "w")
try:
    proc = subprocess.Popen("nosuchprogram", stdout=file)
except OSError:
    pass

try:
    raise RuntimeError() # hack
except:
    pass

file.close()
os.remove("filename")
msg70820 - (view) Author: Hirokazu Yamamoto (ocean-city) * (Python committer) Date: 2008-08-07 12:58
>But still I'm little confused why this code prints "del".

Oh, sorry, kick me. "del" should be printed when interpreter exits. :-)
msg70821 - (view) Author: Martin v. Löwis (loewis) * (Python committer) Date: 2008-08-07 13:05
> Hmm, when exception occurs in some frame, its reference will be
> retained even after exiting function?

Correct. When a traceback is produced, all frames get linked, be
able to print later the traceback with source code information.
Each frame keeps all its local variables.
msg70823 - (view) Author: Hirokazu Yamamoto (ocean-city) * (Python committer) Date: 2008-08-07 13:37
I understand. Thank you.
msg70825 - (view) Author: Antoine Pitrou (pitrou) * (Python committer) Date: 2008-08-07 13:43
You don't need to raise another exception, calling sys.exc_clear()
should be fine. But a cleaner way to write your example is:

def foo():
    with open("a.txt", "w") as io:
        raise RuntimeError()

"with" will automatically close the file when the block exits.
If you are concerned with Python < 2.5 compatibility, use "try: ...
finally:" instead.

And, you're right, the problem doesn't occur at all in Python 3.0
because the exception is cleaned up after the end of the "except:" block
catching it.
History
Date User Action Args
2008-08-07 13:43:13pitrousetstatus: open -> closed
nosy: + pitrou
resolution: not a bug
messages: + msg70825
2008-08-07 13:37:40ocean-citysetmessages: + msg70823
2008-08-07 13:05:07loewissetmessages: + msg70821
2008-08-07 12:58:03ocean-citysetmessages: + msg70820
2008-08-07 12:55:41ocean-citysetmessages: + msg70819
2008-08-07 11:32:18loewissetnosy: + loewis
messages: + msg70817
2008-08-07 10:54:51ocean-citycreate