diff options
author | Benjamin Peterson <benjamin@python.org> | 2010-10-12 22:57:59 (GMT) |
---|---|---|
committer | Benjamin Peterson <benjamin@python.org> | 2010-10-12 22:57:59 (GMT) |
commit | 5c4bfc4af070c5c62f76cf3c2d23a19e7c794c4e (patch) | |
tree | bf62941930ba384c45a44d598e24566caa24e070 | |
parent | 11b1f3dac14f72d7406c96fd7b749ebd8cc16bc9 (diff) | |
download | cpython-5c4bfc4af070c5c62f76cf3c2d23a19e7c794c4e.zip cpython-5c4bfc4af070c5c62f76cf3c2d23a19e7c794c4e.tar.gz cpython-5c4bfc4af070c5c62f76cf3c2d23a19e7c794c4e.tar.bz2 |
prefer clearing global objects to obscure module.__dict__ bugs #10068
-rw-r--r-- | Doc/reference/datamodel.rst | 7 | ||||
-rw-r--r-- | Lib/test/test_module.py | 17 | ||||
-rw-r--r-- | Misc/NEWS | 3 | ||||
-rw-r--r-- | Objects/moduleobject.c | 5 |
4 files changed, 27 insertions, 5 deletions
diff --git a/Doc/reference/datamodel.rst b/Doc/reference/datamodel.rst index 9d084cf..d3b2c15 100644 --- a/Doc/reference/datamodel.rst +++ b/Doc/reference/datamodel.rst @@ -654,6 +654,13 @@ Modules Special read-only attribute: :attr:`__dict__` is the module's namespace as a dictionary object. + .. impl-detail:: + + Because of the way CPython clears module dictionaries, the module + dictionary will be cleared when the module falls out of scope even if the + dictionary still has live references. To avoid this, copy the dictionary + or keep the module around while using its dictionary directly. + .. index:: single: __name__ (module attribute) single: __doc__ (module attribute) diff --git a/Lib/test/test_module.py b/Lib/test/test_module.py index 21ddc9a..7734fb0 100644 --- a/Lib/test/test_module.py +++ b/Lib/test/test_module.py @@ -1,6 +1,6 @@ # Test the module type import unittest -from test.support import run_unittest +from test.support import run_unittest, gc_collect import sys ModuleType = type(sys) @@ -55,14 +55,29 @@ class ModuleTests(unittest.TestCase): {"__name__": "foo", "__doc__": "foodoc", "bar": 42}) self.assertTrue(foo.__dict__ is d) + @unittest.expectedFailure def test_dont_clear_dict(self): # See issue 7140. def f(): foo = ModuleType("foo") foo.bar = 4 return foo + gc_collect() self.assertEqual(f().__dict__["bar"], 4) + def test_clear_dict_in_ref_cycle(self): + destroyed = [] + m = ModuleType("foo") + m.destroyed = destroyed + s = """class A: + def __del__(self): + destroyed.append(1) +a = A()""" + exec(s, m.__dict__) + del m + gc_collect() + self.assertEqual(destroyed, [1]) + def test_main(): run_unittest(ModuleTests) @@ -37,6 +37,9 @@ What's New in Python 3.2 Alpha 3? Core and Builtins ----------------- +- Issue #10068: Global objects which have reference cycles with their module's + dict are now cleared again. This causes issue #7140 to appear again. + - Issue #9738: Document PyErr_SetString() and PyErr_SetFromErrnoWithFilename() encodings. diff --git a/Objects/moduleobject.c b/Objects/moduleobject.c index 3a95261..1e3349d 100644 --- a/Objects/moduleobject.c +++ b/Objects/moduleobject.c @@ -335,10 +335,7 @@ module_dealloc(PyModuleObject *m) if (m->md_def && m->md_def->m_free) m->md_def->m_free(m); if (m->md_dict != NULL) { - /* If we are the only ones holding a reference, we can clear - the dictionary. */ - if (Py_REFCNT(m->md_dict) == 1) - _PyModule_Clear((PyObject *)m); + _PyModule_Clear((PyObject *)m); Py_DECREF(m->md_dict); } if (m->md_state != NULL) |