mirror of https://github.com/python/cpython
when arguments are cells clear the locals slot (backport of #17927)
This commit is contained in:
parent
d486707d2e
commit
e1b4cbc422
|
@ -1,4 +1,6 @@
|
||||||
import unittest
|
import unittest
|
||||||
|
import weakref
|
||||||
|
|
||||||
from test.support import check_syntax_error, cpython_only, run_unittest
|
from test.support import check_syntax_error, cpython_only, run_unittest
|
||||||
|
|
||||||
|
|
||||||
|
@ -713,6 +715,33 @@ class ScopeTests(unittest.TestCase):
|
||||||
def b():
|
def b():
|
||||||
global a
|
global a
|
||||||
|
|
||||||
|
@cpython_only
|
||||||
|
def testCellLeak(self):
|
||||||
|
# Issue 17927.
|
||||||
|
#
|
||||||
|
# The issue was that if self was part of a cycle involving the
|
||||||
|
# frame of a method call, *and* the method contained a nested
|
||||||
|
# function referencing self, thereby forcing 'self' into a
|
||||||
|
# cell, setting self to None would not be enough to break the
|
||||||
|
# frame -- the frame had another reference to the instance,
|
||||||
|
# which could not be cleared by the code running in the frame
|
||||||
|
# (though it will be cleared when the frame is collected).
|
||||||
|
# Without the lambda, setting self to None is enough to break
|
||||||
|
# the cycle.
|
||||||
|
class Tester:
|
||||||
|
def dig(self):
|
||||||
|
if 0:
|
||||||
|
lambda: self
|
||||||
|
try:
|
||||||
|
1/0
|
||||||
|
except Exception as exc:
|
||||||
|
self.exc = exc
|
||||||
|
self = None # Break the cycle
|
||||||
|
tester = Tester()
|
||||||
|
tester.dig()
|
||||||
|
ref = weakref.ref(tester)
|
||||||
|
del tester
|
||||||
|
self.assertIsNone(ref())
|
||||||
|
|
||||||
|
|
||||||
def test_main():
|
def test_main():
|
||||||
|
|
|
@ -130,6 +130,19 @@ class TestSuper(unittest.TestCase):
|
||||||
super()
|
super()
|
||||||
self.assertRaises(RuntimeError, X().f)
|
self.assertRaises(RuntimeError, X().f)
|
||||||
|
|
||||||
|
def test_cell_as_self(self):
|
||||||
|
class X:
|
||||||
|
def meth(self):
|
||||||
|
super()
|
||||||
|
|
||||||
|
def f():
|
||||||
|
k = X()
|
||||||
|
def g():
|
||||||
|
return k
|
||||||
|
return g
|
||||||
|
c = f().__closure__[0]
|
||||||
|
self.assertRaises(TypeError, X.meth, c)
|
||||||
|
|
||||||
|
|
||||||
def test_main():
|
def test_main():
|
||||||
support.run_unittest(TestSuper)
|
support.run_unittest(TestSuper)
|
||||||
|
|
|
@ -12,6 +12,9 @@ What's New in Python 3.3.2?
|
||||||
Core and Builtins
|
Core and Builtins
|
||||||
-----------------
|
-----------------
|
||||||
|
|
||||||
|
- Issue #17927: Frame objects kept arguments alive if they had been copied into
|
||||||
|
a cell, even if the cell was cleared.
|
||||||
|
|
||||||
- Issue #17237: Fix crash in the ASCII decoder on m68k.
|
- Issue #17237: Fix crash in the ASCII decoder on m68k.
|
||||||
|
|
||||||
- Issue #17408: Avoid using an obsolete instance of the copyreg module when
|
- Issue #17408: Avoid using an obsolete instance of the copyreg module when
|
||||||
|
|
|
@ -6519,6 +6519,18 @@ super_init(PyObject *self, PyObject *args, PyObject *kwds)
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
obj = f->f_localsplus[0];
|
obj = f->f_localsplus[0];
|
||||||
|
if (obj == NULL && co->co_cell2arg) {
|
||||||
|
/* The first argument might be a cell. */
|
||||||
|
n = PyTuple_GET_SIZE(co->co_cellvars);
|
||||||
|
for (i = 0; i < n; i++) {
|
||||||
|
if (co->co_cell2arg[i] == 0) {
|
||||||
|
PyObject *cell = f->f_localsplus[co->co_nlocals + i];
|
||||||
|
assert(PyCell_Check(cell));
|
||||||
|
obj = PyCell_GET(cell);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
if (obj == NULL) {
|
if (obj == NULL) {
|
||||||
PyErr_SetString(PyExc_RuntimeError,
|
PyErr_SetString(PyExc_RuntimeError,
|
||||||
"super(): arg[0] deleted");
|
"super(): arg[0] deleted");
|
||||||
|
|
|
@ -3403,10 +3403,14 @@ PyEval_EvalCodeEx(PyObject *_co, PyObject *globals, PyObject *locals,
|
||||||
int arg;
|
int arg;
|
||||||
/* Possibly account for the cell variable being an argument. */
|
/* Possibly account for the cell variable being an argument. */
|
||||||
if (co->co_cell2arg != NULL &&
|
if (co->co_cell2arg != NULL &&
|
||||||
(arg = co->co_cell2arg[i]) != CO_CELL_NOT_AN_ARG)
|
(arg = co->co_cell2arg[i]) != CO_CELL_NOT_AN_ARG) {
|
||||||
c = PyCell_New(GETLOCAL(arg));
|
c = PyCell_New(GETLOCAL(arg));
|
||||||
else
|
/* Clear the local copy. */
|
||||||
|
SETLOCAL(arg, NULL);
|
||||||
|
}
|
||||||
|
else {
|
||||||
c = PyCell_New(NULL);
|
c = PyCell_New(NULL);
|
||||||
|
}
|
||||||
if (c == NULL)
|
if (c == NULL)
|
||||||
goto fail;
|
goto fail;
|
||||||
SETLOCAL(co->co_nlocals + i, c);
|
SETLOCAL(co->co_nlocals + i, c);
|
||||||
|
|
Loading…
Reference in New Issue