mirror of https://github.com/python/cpython
prefer clearing global objects to obscure module.__dict__ bugs #10068
This commit is contained in:
parent
11b1f3dac1
commit
5c4bfc4af0
|
@ -654,6 +654,13 @@ Modules
|
||||||
Special read-only attribute: :attr:`__dict__` is the module's namespace as a
|
Special read-only attribute: :attr:`__dict__` is the module's namespace as a
|
||||||
dictionary object.
|
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::
|
.. index::
|
||||||
single: __name__ (module attribute)
|
single: __name__ (module attribute)
|
||||||
single: __doc__ (module attribute)
|
single: __doc__ (module attribute)
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
# Test the module type
|
# Test the module type
|
||||||
import unittest
|
import unittest
|
||||||
from test.support import run_unittest
|
from test.support import run_unittest, gc_collect
|
||||||
|
|
||||||
import sys
|
import sys
|
||||||
ModuleType = type(sys)
|
ModuleType = type(sys)
|
||||||
|
@ -55,14 +55,29 @@ class ModuleTests(unittest.TestCase):
|
||||||
{"__name__": "foo", "__doc__": "foodoc", "bar": 42})
|
{"__name__": "foo", "__doc__": "foodoc", "bar": 42})
|
||||||
self.assertTrue(foo.__dict__ is d)
|
self.assertTrue(foo.__dict__ is d)
|
||||||
|
|
||||||
|
@unittest.expectedFailure
|
||||||
def test_dont_clear_dict(self):
|
def test_dont_clear_dict(self):
|
||||||
# See issue 7140.
|
# See issue 7140.
|
||||||
def f():
|
def f():
|
||||||
foo = ModuleType("foo")
|
foo = ModuleType("foo")
|
||||||
foo.bar = 4
|
foo.bar = 4
|
||||||
return foo
|
return foo
|
||||||
|
gc_collect()
|
||||||
self.assertEqual(f().__dict__["bar"], 4)
|
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():
|
def test_main():
|
||||||
run_unittest(ModuleTests)
|
run_unittest(ModuleTests)
|
||||||
|
|
||||||
|
|
|
@ -37,6 +37,9 @@ What's New in Python 3.2 Alpha 3?
|
||||||
Core and Builtins
|
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()
|
- Issue #9738: Document PyErr_SetString() and PyErr_SetFromErrnoWithFilename()
|
||||||
encodings.
|
encodings.
|
||||||
|
|
||||||
|
|
|
@ -335,10 +335,7 @@ module_dealloc(PyModuleObject *m)
|
||||||
if (m->md_def && m->md_def->m_free)
|
if (m->md_def && m->md_def->m_free)
|
||||||
m->md_def->m_free(m);
|
m->md_def->m_free(m);
|
||||||
if (m->md_dict != NULL) {
|
if (m->md_dict != NULL) {
|
||||||
/* If we are the only ones holding a reference, we can clear
|
_PyModule_Clear((PyObject *)m);
|
||||||
the dictionary. */
|
|
||||||
if (Py_REFCNT(m->md_dict) == 1)
|
|
||||||
_PyModule_Clear((PyObject *)m);
|
|
||||||
Py_DECREF(m->md_dict);
|
Py_DECREF(m->md_dict);
|
||||||
}
|
}
|
||||||
if (m->md_state != NULL)
|
if (m->md_state != NULL)
|
||||||
|
|
Loading…
Reference in New Issue