cpython: 2b4b289c1abb (original) (raw)
Mercurial > cpython
changeset 83772:2b4b289c1abb 3.3
when arguments are cells clear the locals slot (backport of #17927) [#17927]
Benjamin Peterson benjamin@python.org | |
---|---|
date | Tue, 14 May 2013 22:31:26 -0500 |
parents | e2288953e9f1 |
children | bb8093e427f9 2bc63e65b3bf |
files | Lib/test/test_scope.py Lib/test/test_super.py Misc/NEWS Objects/typeobject.c Python/ceval.c |
diffstat | 5 files changed, 63 insertions(+), 2 deletions(-)[+] [-] Lib/test/test_scope.py 29 Lib/test/test_super.py 13 Misc/NEWS 3 Objects/typeobject.c 12 Python/ceval.c 8 |
line wrap: on
line diff
--- a/Lib/test/test_scope.py +++ b/Lib/test/test_scope.py @@ -1,4 +1,6 @@ import unittest +import weakref + from test.support import check_syntax_error, cpython_only, run_unittest @@ -713,6 +715,33 @@ class ScopeTests(unittest.TestCase): def b(): global a
- @cpython_only
- def testCellLeak(self):
# Issue 17927.[](#l1.16)
#[](#l1.17)
# The issue was that if self was part of a cycle involving the[](#l1.18)
# frame of a method call, *and* the method contained a nested[](#l1.19)
# function referencing self, thereby forcing 'self' into a[](#l1.20)
# cell, setting self to None would not be enough to break the[](#l1.21)
# frame -- the frame had another reference to the instance,[](#l1.22)
# which could not be cleared by the code running in the frame[](#l1.23)
# (though it will be cleared when the frame is collected).[](#l1.24)
# Without the lambda, setting self to None is enough to break[](#l1.25)
# the cycle.[](#l1.26)
class Tester:[](#l1.27)
def dig(self):[](#l1.28)
if 0:[](#l1.29)
lambda: self[](#l1.30)
try:[](#l1.31)
1/0[](#l1.32)
except Exception as exc:[](#l1.33)
self.exc = exc[](#l1.34)
self = None # Break the cycle[](#l1.35)
tester = Tester()[](#l1.36)
tester.dig()[](#l1.37)
ref = weakref.ref(tester)[](#l1.38)
del tester[](#l1.39)
self.assertIsNone(ref())[](#l1.40)
--- a/Lib/test/test_super.py +++ b/Lib/test/test_super.py @@ -130,6 +130,19 @@ class TestSuper(unittest.TestCase): super() self.assertRaises(RuntimeError, X().f)
def f():[](#l2.12)
k = X()[](#l2.13)
def g():[](#l2.14)
return k[](#l2.15)
return g[](#l2.16)
c = f().__closure__[0][](#l2.17)
self.assertRaises(TypeError, X.meth, c)[](#l2.18)
+ def test_main(): support.run_unittest(TestSuper)
--- a/Misc/NEWS +++ b/Misc/NEWS @@ -12,6 +12,9 @@ What's New in Python 3.3.2? Core and Builtins ----------------- +- Issue #17927: Frame objects kept arguments alive if they had been copied into
- Issue #17237: Fix crash in the ASCII decoder on m68k.
- Issue #17408: Avoid using an obsolete instance of the copyreg module when
--- a/Objects/typeobject.c +++ b/Objects/typeobject.c @@ -6519,6 +6519,18 @@ super_init(PyObject *self, PyObject *arg return -1; } obj = f->f_localsplus[0];
if (obj == NULL && co->co_cell2arg) {[](#l4.7)
/* The first argument might be a cell. */[](#l4.8)
n = PyTuple_GET_SIZE(co->co_cellvars);[](#l4.9)
for (i = 0; i < n; i++) {[](#l4.10)
if (co->co_cell2arg[i] == 0) {[](#l4.11)
PyObject *cell = f->f_localsplus[co->co_nlocals + i];[](#l4.12)
assert(PyCell_Check(cell));[](#l4.13)
obj = PyCell_GET(cell);[](#l4.14)
break;[](#l4.15)
}[](#l4.16)
}[](#l4.17)
}[](#l4.18) if (obj == NULL) {[](#l4.19) PyErr_SetString(PyExc_RuntimeError,[](#l4.20) "super(): arg[0] deleted");[](#l4.21)
--- a/Python/ceval.c +++ b/Python/ceval.c @@ -3403,10 +3403,14 @@ PyEval_EvalCodeEx(PyObject _co, PyObjec int arg; / Possibly account for the cell variable being an argument. */ if (co->co_cell2arg != NULL &&
(arg = co->co_cell2arg[i]) != CO_CELL_NOT_AN_ARG)[](#l5.7)
(arg = co->co_cell2arg[i]) != CO_CELL_NOT_AN_ARG) {[](#l5.8) c = PyCell_New(GETLOCAL(arg));[](#l5.9)
else[](#l5.10)
/* Clear the local copy. */[](#l5.11)
SETLOCAL(arg, NULL);[](#l5.12)
}[](#l5.13)
else {[](#l5.14) c = PyCell_New(NULL);[](#l5.15)
}[](#l5.16) if (c == NULL)[](#l5.17) goto fail;[](#l5.18) SETLOCAL(co->co_nlocals + i, c);[](#l5.19)