mirror of https://github.com/python/cpython
Moved clear_carefully() to _PyModule_Clear() in moduleobject.c
(modified) and use that. Some differences in the cleanup algorithm: - Clear __main__ before the other modules. - Delete more sys variables: including ps1, ps2, exitfunc, argv, and even path -- this will prevent new imports! - Restore stdin, stdout, stderr from __stdin__, __stdout__, __stderr__, effectively deleting hooks that the user might have installed -- so their (the hooks') destructors will run.
This commit is contained in:
parent
bd36dbaaa5
commit
05f9dce34f
100
Python/import.c
100
Python/import.c
|
@ -125,63 +125,21 @@ PyImport_GetModuleDict()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* Helper for PyImport_Cleanup */
|
|
||||||
|
|
||||||
static void
|
|
||||||
clear_carefully(d)
|
|
||||||
PyObject *d;
|
|
||||||
{
|
|
||||||
/* To make the execution order of destructors for global
|
|
||||||
objects a bit more predictable, we first zap all objects
|
|
||||||
whose name starts with a single underscore, before we clear
|
|
||||||
the entire dictionary. We zap them by replacing them with
|
|
||||||
None, rather than deleting them from the dictionary, to
|
|
||||||
avoid rehashing the dictionary (to some extent). */
|
|
||||||
|
|
||||||
int pos;
|
|
||||||
PyObject *key, *value;
|
|
||||||
|
|
||||||
Py_INCREF(d); /* Prevent it from being deleted recursively */
|
|
||||||
|
|
||||||
/* First, clear only names starting with a single underscore */
|
|
||||||
pos = 0;
|
|
||||||
while (PyDict_Next(d, &pos, &key, &value)) {
|
|
||||||
if (value != Py_None && PyString_Check(key)) {
|
|
||||||
char *s = PyString_AsString(key);
|
|
||||||
if (s[0] == '_' && s[1] != '_') {
|
|
||||||
if (Py_VerboseFlag > 1)
|
|
||||||
fprintf(stderr, "# clear[1] %s\n", s);
|
|
||||||
PyDict_SetItem(d, key, Py_None);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Next, clear all names except those starting with two underscores */
|
|
||||||
pos = 0;
|
|
||||||
while (PyDict_Next(d, &pos, &key, &value)) {
|
|
||||||
if (value != Py_None && PyString_Check(key)) {
|
|
||||||
char *s = PyString_AsString(key);
|
|
||||||
if (s[0] != '_' || s[1] != '_') {
|
|
||||||
if (Py_VerboseFlag > 1)
|
|
||||||
fprintf(stderr, "# clear[2] %s\n", s);
|
|
||||||
PyDict_SetItem(d, key, Py_None);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
PyDict_Clear(d); /* Finally, clear all names */
|
|
||||||
|
|
||||||
Py_DECREF(d); /* Match INCREF at top */
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/* List of names to clear in sys */
|
/* List of names to clear in sys */
|
||||||
static char* sys_deletes[] = {
|
static char* sys_deletes[] = {
|
||||||
|
"path", "argv", "ps1", "ps2", "exitfunc",
|
||||||
"exc_type", "exc_value", "exc_traceback",
|
"exc_type", "exc_value", "exc_traceback",
|
||||||
"last_type", "last_value", "last_traceback",
|
"last_type", "last_value", "last_traceback",
|
||||||
NULL
|
NULL
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static char* sys_files[] = {
|
||||||
|
"stdin", "__stdin__",
|
||||||
|
"stdout", "__stdout__",
|
||||||
|
"stderr", "__stderr__",
|
||||||
|
NULL
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
/* Un-initialize things, as good as we can */
|
/* Un-initialize things, as good as we can */
|
||||||
|
|
||||||
|
@ -213,12 +171,30 @@ PyImport_Cleanup()
|
||||||
value = PyDict_GetItemString(modules, "sys");
|
value = PyDict_GetItemString(modules, "sys");
|
||||||
if (value != NULL && PyModule_Check(value)) {
|
if (value != NULL && PyModule_Check(value)) {
|
||||||
char **p;
|
char **p;
|
||||||
|
PyObject *v;
|
||||||
dict = PyModule_GetDict(value);
|
dict = PyModule_GetDict(value);
|
||||||
for (p = sys_deletes; *p != NULL; p++) {
|
for (p = sys_deletes; *p != NULL; p++) {
|
||||||
if (Py_VerboseFlag)
|
if (Py_VerboseFlag)
|
||||||
fprintf(stderr, "# clear sys.%s\n", *p);
|
fprintf(stderr, "# clear sys.%s\n", *p);
|
||||||
PyDict_SetItemString(dict, *p, Py_None);
|
PyDict_SetItemString(dict, *p, Py_None);
|
||||||
}
|
}
|
||||||
|
for (p = sys_files; *p != NULL; p+=2) {
|
||||||
|
if (Py_VerboseFlag)
|
||||||
|
fprintf(stderr, "# restore sys.%s\n", *p);
|
||||||
|
v = PyDict_GetItemString(dict, *(p+1));
|
||||||
|
if (v == NULL)
|
||||||
|
v = Py_None;
|
||||||
|
PyDict_SetItemString(dict, *p, v);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* First, delete __main__ */
|
||||||
|
value = PyDict_GetItemString(modules, "__main__");
|
||||||
|
if (value != NULL && PyModule_Check(value)) {
|
||||||
|
if (Py_VerboseFlag)
|
||||||
|
fprintf(stderr, "# cleanup __main__\n");
|
||||||
|
_PyModule_Clear(value);
|
||||||
|
PyDict_SetItemString(modules, "__main__", Py_None);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* The special treatment of __builtin__ here is because even
|
/* The special treatment of __builtin__ here is because even
|
||||||
|
@ -235,7 +211,7 @@ PyImport_Cleanup()
|
||||||
also marks them as "non existent" so they won't be
|
also marks them as "non existent" so they won't be
|
||||||
re-imported. */
|
re-imported. */
|
||||||
|
|
||||||
/* First, repeatedly delete modules with a reference count of
|
/* Next, repeatedly delete modules with a reference count of
|
||||||
one (skipping __builtin__ and sys) and delete them */
|
one (skipping __builtin__ and sys) and delete them */
|
||||||
do {
|
do {
|
||||||
ndone = 0;
|
ndone = 0;
|
||||||
|
@ -245,7 +221,6 @@ PyImport_Cleanup()
|
||||||
continue;
|
continue;
|
||||||
if (PyModule_Check(value)) {
|
if (PyModule_Check(value)) {
|
||||||
name = PyString_AsString(key);
|
name = PyString_AsString(key);
|
||||||
dict = PyModule_GetDict(value);
|
|
||||||
if (strcmp(name, "__builtin__") == 0)
|
if (strcmp(name, "__builtin__") == 0)
|
||||||
continue;
|
continue;
|
||||||
if (strcmp(name, "sys") == 0)
|
if (strcmp(name, "sys") == 0)
|
||||||
|
@ -253,36 +228,25 @@ PyImport_Cleanup()
|
||||||
if (Py_VerboseFlag)
|
if (Py_VerboseFlag)
|
||||||
fprintf(stderr,
|
fprintf(stderr,
|
||||||
"# cleanup[1] %s\n", name);
|
"# cleanup[1] %s\n", name);
|
||||||
clear_carefully(dict);
|
_PyModule_Clear(value);
|
||||||
PyDict_SetItem(modules, key, Py_None);
|
PyDict_SetItem(modules, key, Py_None);
|
||||||
ndone++;
|
ndone++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} while (ndone > 0);
|
} while (ndone > 0);
|
||||||
|
|
||||||
/* Next, delete __main__ if it's still there */
|
|
||||||
value = PyDict_GetItemString(modules, "__main__");
|
|
||||||
if (value != NULL && PyModule_Check(value)) {
|
|
||||||
dict = PyModule_GetDict(value);
|
|
||||||
if (Py_VerboseFlag)
|
|
||||||
fprintf(stderr, "# cleanup __main__\n");
|
|
||||||
clear_carefully(dict);
|
|
||||||
PyDict_SetItemString(modules, "__main__", Py_None);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Next, delete all modules (still skipping __builtin__ and sys) */
|
/* Next, delete all modules (still skipping __builtin__ and sys) */
|
||||||
pos = 0;
|
pos = 0;
|
||||||
while (PyDict_Next(modules, &pos, &key, &value)) {
|
while (PyDict_Next(modules, &pos, &key, &value)) {
|
||||||
if (PyModule_Check(value)) {
|
if (PyModule_Check(value)) {
|
||||||
name = PyString_AsString(key);
|
name = PyString_AsString(key);
|
||||||
dict = PyModule_GetDict(value);
|
|
||||||
if (strcmp(name, "__builtin__") == 0)
|
if (strcmp(name, "__builtin__") == 0)
|
||||||
continue;
|
continue;
|
||||||
if (strcmp(name, "sys") == 0)
|
if (strcmp(name, "sys") == 0)
|
||||||
continue;
|
continue;
|
||||||
if (Py_VerboseFlag)
|
if (Py_VerboseFlag)
|
||||||
fprintf(stderr, "# cleanup[2] %s\n", name);
|
fprintf(stderr, "# cleanup[2] %s\n", name);
|
||||||
clear_carefully(dict);
|
_PyModule_Clear(value);
|
||||||
PyDict_SetItem(modules, key, Py_None);
|
PyDict_SetItem(modules, key, Py_None);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -290,18 +254,16 @@ PyImport_Cleanup()
|
||||||
/* Next, delete sys and __builtin__ (in that order) */
|
/* Next, delete sys and __builtin__ (in that order) */
|
||||||
value = PyDict_GetItemString(modules, "sys");
|
value = PyDict_GetItemString(modules, "sys");
|
||||||
if (value != NULL && PyModule_Check(value)) {
|
if (value != NULL && PyModule_Check(value)) {
|
||||||
dict = PyModule_GetDict(value);
|
|
||||||
if (Py_VerboseFlag)
|
if (Py_VerboseFlag)
|
||||||
fprintf(stderr, "# cleanup sys\n");
|
fprintf(stderr, "# cleanup sys\n");
|
||||||
clear_carefully(dict);
|
_PyModule_Clear(value);
|
||||||
PyDict_SetItemString(modules, "sys", Py_None);
|
PyDict_SetItemString(modules, "sys", Py_None);
|
||||||
}
|
}
|
||||||
value = PyDict_GetItemString(modules, "__builtin__");
|
value = PyDict_GetItemString(modules, "__builtin__");
|
||||||
if (value != NULL && PyModule_Check(value)) {
|
if (value != NULL && PyModule_Check(value)) {
|
||||||
dict = PyModule_GetDict(value);
|
|
||||||
if (Py_VerboseFlag)
|
if (Py_VerboseFlag)
|
||||||
fprintf(stderr, "# cleanup __builtin__\n");
|
fprintf(stderr, "# cleanup __builtin__\n");
|
||||||
clear_carefully(dict); /* XXX Is this necessary? */
|
_PyModule_Clear(value);
|
||||||
PyDict_SetItemString(modules, "__builtin__", Py_None);
|
PyDict_SetItemString(modules, "__builtin__", Py_None);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue