summaryrefslogtreecommitdiffstats
path: root/Python
diff options
context:
space:
mode:
authorSerhiy Storchaka <storchaka@gmail.com>2014-02-10 16:21:34 (GMT)
committerSerhiy Storchaka <storchaka@gmail.com>2014-02-10 16:21:34 (GMT)
commit87a5c515d03f3e2215f3da7b90a4b848ac510879 (patch)
tree84a23e66140538f0d8b870379826b809be2c65b7 /Python
parent8f9f0f12e845034080525c6a80d52215533cb2a4 (diff)
downloadcpython-87a5c515d03f3e2215f3da7b90a4b848ac510879.zip
cpython-87a5c515d03f3e2215f3da7b90a4b848ac510879.tar.gz
cpython-87a5c515d03f3e2215f3da7b90a4b848ac510879.tar.bz2
Issue #19255: The builtins module is restored to initial value before
cleaning other modules. The sys and builtins modules are cleaned last.
Diffstat (limited to 'Python')
-rw-r--r--Python/import.c87
-rw-r--r--Python/pystate.c2
2 files changed, 55 insertions, 34 deletions
diff --git a/Python/import.c b/Python/import.c
index d0115e4..207dbce 100644
--- a/Python/import.c
+++ b/Python/import.c
@@ -49,9 +49,13 @@ class fs_unicode_converter(CConverter):
void
_PyImport_Init(void)
{
+ PyInterpreterState *interp = PyThreadState_Get()->interp;
initstr = PyUnicode_InternFromString("__init__");
if (initstr == NULL)
Py_FatalError("Can't initialize import variables");
+ interp->builtins_copy = PyDict_Copy(interp->builtins);
+ if (interp->builtins_copy == NULL)
+ Py_FatalError("Can't backup builtins dict");
}
void
@@ -397,8 +401,10 @@ PyImport_Cleanup(void)
PyObject *key, *value, *dict;
PyInterpreterState *interp = PyThreadState_GET()->interp;
PyObject *modules = interp->modules;
- PyObject *builtins = interp->builtins;
+ PyObject *builtins_mod = NULL;
+ PyObject *sys_mod = NULL;
PyObject *weaklist = NULL;
+ char **p;
if (modules == NULL)
return; /* Already done */
@@ -411,31 +417,22 @@ PyImport_Cleanup(void)
/* XXX Perhaps these precautions are obsolete. Who knows? */
- value = PyDict_GetItemString(modules, "builtins");
- if (value != NULL && PyModule_Check(value)) {
- dict = PyModule_GetDict(value);
+ if (Py_VerboseFlag)
+ PySys_WriteStderr("# clear builtins._\n");
+ PyDict_SetItemString(interp->builtins, "_", Py_None);
+
+ for (p = sys_deletes; *p != NULL; p++) {
if (Py_VerboseFlag)
- PySys_WriteStderr("# clear builtins._\n");
- PyDict_SetItemString(dict, "_", Py_None);
- }
- value = PyDict_GetItemString(modules, "sys");
- if (value != NULL && PyModule_Check(value)) {
- char **p;
- PyObject *v;
- dict = PyModule_GetDict(value);
- for (p = sys_deletes; *p != NULL; p++) {
- if (Py_VerboseFlag)
- PySys_WriteStderr("# clear sys.%s\n", *p);
- PyDict_SetItemString(dict, *p, Py_None);
- }
- for (p = sys_files; *p != NULL; p+=2) {
- if (Py_VerboseFlag)
- PySys_WriteStderr("# restore sys.%s\n", *p);
- v = PyDict_GetItemString(dict, *(p+1));
- if (v == NULL)
- v = Py_None;
- PyDict_SetItemString(dict, *p, v);
- }
+ PySys_WriteStderr("# clear sys.%s\n", *p);
+ PyDict_SetItemString(interp->sysdict, *p, Py_None);
+ }
+ for (p = sys_files; *p != NULL; p+=2) {
+ if (Py_VerboseFlag)
+ PySys_WriteStderr("# restore sys.%s\n", *p);
+ value = PyDict_GetItemString(interp->sysdict, *(p+1));
+ if (value == NULL)
+ value = Py_None;
+ PyDict_SetItemString(interp->sysdict, *p, value);
}
/* We prepare a list which will receive (name, weakref) tuples of
@@ -473,11 +470,15 @@ PyImport_Cleanup(void)
/* Clear the modules dict. */
PyDict_Clear(modules);
- /* Replace the interpreter's reference to builtins with an empty dict
- (module globals still have a reference to the original builtins). */
- builtins = interp->builtins;
- interp->builtins = PyDict_New();
- Py_DECREF(builtins);
+ /* Restore the original builtins dict, to ensure that any
+ user data gets cleared. */
+ dict = PyDict_Copy(interp->builtins);
+ if (dict == NULL)
+ PyErr_Clear();
+ PyDict_Clear(interp->builtins);
+ if (PyDict_Update(interp->builtins, interp->builtins_copy))
+ PyErr_Clear();
+ Py_XDECREF(dict);
/* Clear module dict copies stored in the interpreter state */
_PyState_ClearModules();
/* Collect references */
@@ -488,7 +489,15 @@ PyImport_Cleanup(void)
/* Now, if there are any modules left alive, clear their globals to
minimize potential leaks. All C extension modules actually end
- up here, since they are kept alive in the interpreter state. */
+ up here, since they are kept alive in the interpreter state.
+
+ The special treatment of "builtins" here is because even
+ when it's not referenced as a module, its dictionary is
+ referenced by almost every module's __builtins__. Since
+ deleting a module clears its dictionary (even if there are
+ references left to it), we need to delete the "builtins"
+ module last. Likewise, we don't delete sys until the very
+ end because it is implicitly referenced (e.g. by print). */
if (weaklist != NULL) {
Py_ssize_t i, n;
n = PyList_GET_SIZE(weaklist);
@@ -498,17 +507,27 @@ PyImport_Cleanup(void)
PyObject *mod = PyWeakref_GET_OBJECT(PyTuple_GET_ITEM(tup, 1));
if (mod == Py_None)
continue;
- Py_INCREF(mod);
assert(PyModule_Check(mod));
+ dict = PyModule_GetDict(mod);
+ if (dict == interp->builtins || dict == interp->sysdict)
+ continue;
+ Py_INCREF(mod);
if (Py_VerboseFlag && PyUnicode_Check(name))
- PySys_FormatStderr("# cleanup[3] wiping %U\n",
- name, mod);
+ PySys_FormatStderr("# cleanup[3] wiping %U\n", name);
_PyModule_Clear(mod);
Py_DECREF(mod);
}
Py_DECREF(weaklist);
}
+ /* Next, delete sys and builtins (in that order) */
+ if (Py_VerboseFlag)
+ PySys_FormatStderr("# cleanup[3] wiping sys\n");
+ _PyModule_ClearDict(interp->sysdict);
+ if (Py_VerboseFlag)
+ PySys_FormatStderr("# cleanup[3] wiping builtins\n");
+ _PyModule_ClearDict(interp->builtins);
+
/* Clear and delete the modules directory. Actual modules will
still be there only if imported during the execution of some
destructor. */
diff --git a/Python/pystate.c b/Python/pystate.c
index 19fceb7..2ac2fd5 100644
--- a/Python/pystate.c
+++ b/Python/pystate.c
@@ -72,6 +72,7 @@ PyInterpreterState_New(void)
interp->modules_by_index = NULL;
interp->sysdict = NULL;
interp->builtins = NULL;
+ interp->builtins_copy = NULL;
interp->tstate_head = NULL;
interp->codec_search_path = NULL;
interp->codec_search_cache = NULL;
@@ -115,6 +116,7 @@ PyInterpreterState_Clear(PyInterpreterState *interp)
Py_CLEAR(interp->modules_by_index);
Py_CLEAR(interp->sysdict);
Py_CLEAR(interp->builtins);
+ Py_CLEAR(interp->builtins_copy);
Py_CLEAR(interp->importlib);
}