diff --git a/Include/internal/pycore_frame.h b/Include/internal/pycore_frame.h index 5806cf05f174a9..97bce3143d7def 100644 --- a/Include/internal/pycore_frame.h +++ b/Include/internal/pycore_frame.h @@ -22,6 +22,7 @@ struct _frame { char f_trace_lines; /* Emit per-line trace events? */ char f_trace_opcodes; /* Emit per-opcode trace events? */ char f_fast_as_locals; /* Have the fast locals of this frame been converted to a dict? */ + PyObject* f_weakreflist; /* Weak ref support */ /* The frame data, if this frame object owns the frame */ PyObject *_f_frame_data[1]; }; diff --git a/Lib/test/test_frame.py b/Lib/test/test_frame.py index 6bb0144e9b1ed7..91a453c32dcc9d 100644 --- a/Lib/test/test_frame.py +++ b/Lib/test/test_frame.py @@ -205,6 +205,18 @@ def test_f_lineno_del_segfault(self): with self.assertRaises(AttributeError): del f.f_lineno + def test_weakref_support(self): + wkd = weakref.WeakKeyDictionary() + def _test(): + f, outer, inner = self.make_frames() + for frame in (f, outer, inner): + wkd[frame] = True + for frame in (f, outer, inner): + self.assertEqual(wkd[frame], True) + _test() + gc.collect() + self.assertEqual(len(wkd), 0) + class ReprTest(unittest.TestCase): """ diff --git a/Lib/test/test_sys.py b/Lib/test/test_sys.py index fb578c5ae6e5d5..14b6639044c555 100644 --- a/Lib/test/test_sys.py +++ b/Lib/test/test_sys.py @@ -1445,7 +1445,7 @@ class C(object): pass def func(): return sys._getframe() x = func() - check(x, size('3Pi3c7P2ic??2P')) + check(x, size('3Pi3c7P2ic??P2P')) # function def func(): pass check(func, size('14Pi')) diff --git a/Objects/frameobject.c b/Objects/frameobject.c index 19bd4b10780b91..c3be197aab491f 100644 --- a/Objects/frameobject.c +++ b/Objects/frameobject.c @@ -862,6 +862,10 @@ frame_dealloc(PyFrameObject *f) _PyObject_GC_UNTRACK(f); } + if (f->f_weakreflist != NULL) { + PyObject_ClearWeakRefs((PyObject *)f); + } + Py_TRASHCAN_BEGIN(f, frame_dealloc); PyCodeObject *co = NULL; @@ -997,7 +1001,7 @@ PyTypeObject PyFrame_Type = { (traverseproc)frame_traverse, /* tp_traverse */ (inquiry)frame_tp_clear, /* tp_clear */ 0, /* tp_richcompare */ - 0, /* tp_weaklistoffset */ + OFF(f_weakreflist), /* tp_weaklistoffset */ 0, /* tp_iter */ 0, /* tp_iternext */ frame_methods, /* tp_methods */ @@ -1031,6 +1035,7 @@ _PyFrame_New_NoTrack(PyCodeObject *code) f->f_trace_opcodes = 0; f->f_fast_as_locals = 0; f->f_lineno = 0; + f->f_weakreflist = NULL; return f; }