fixed ref-count bug in try-except handling
authorStefan Behnel <scoder@users.berlios.de>
Mon, 17 Nov 2008 13:35:05 +0000 (14:35 +0100)
committerStefan Behnel <scoder@users.berlios.de>
Mon, 17 Nov 2008 13:35:05 +0000 (14:35 +0100)
Cython/Compiler/Nodes.py
tests/run/exceptionrefcount.pyx [new file with mode: 0644]

index 56b69d8f2f409e2a99b194f07015239e9f417472..6317e8150b911eb9a1dc09c63110c658505f5ebc 100644 (file)
@@ -3960,6 +3960,8 @@ class TryExceptStatNode(StatNode):
             self.else_clause.generate_execution_code(code)
             code.putln(
                 "}")
+        for var in Naming.exc_save_vars:
+            code.put_xdecref_clear(var, py_object_type)
         code.put_goto(try_end_label)
         code.put_label(our_error_label)
         code.put_var_xdecrefs_clear(self.cleanup_list)
diff --git a/tests/run/exceptionrefcount.pyx b/tests/run/exceptionrefcount.pyx
new file mode 100644 (file)
index 0000000..4c8d645
--- /dev/null
@@ -0,0 +1,55 @@
+__doc__ = u"""
+>>> class SampleException(Exception): pass
+>>> import sys
+
+>>> def assert_refcount(rc1, rc2, func):
+...     # test ref-counts, but allow a bit of freedom
+...     assert rc2 <= rc1 + 4, "%s, before: %d, after %d" % (
+...         func.__name__, rc1, rc2)
+
+>>> def run_test(repeat, test_func):
+...     initial_refcount = sys.getrefcount(SampleException)
+...     for i in range(repeat):
+...         try: raise SampleException
+...         except:
+...             refcount1 = sys.getrefcount(SampleException)
+...             test_func()
+...             refcount2 = sys.getrefcount(SampleException)
+...             
+...             assert_refcount(refcount1, refcount2, test_func)
+...             assert_refcount(initial_refcount, refcount2, test_func)
+...         refcount3 = sys.getrefcount(SampleException)
+...         assert_refcount(refcount1, refcount3, test_func)
+...         assert_refcount(initial_refcount, refcount3, test_func)
+
+>>> run_test(50, test_no_exception_else)
+>>> run_test(50, test_no_exception)
+>>> run_test(50, test_exception)
+>>> run_test(50, test_finally)
+"""
+
+def test_no_exception():
+    try:
+        a = 1+1
+    except:
+        pass
+
+def test_no_exception_else():
+    try:
+        a = 1+1
+    except:
+        pass
+    else:
+        b = 1+1
+
+def test_exception():
+    try:
+        raise TypeError
+    except:
+        pass
+
+def test_finally():
+    try:
+        a = 1+1
+    finally:
+        b = 1+1