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:
Guido van Rossum 1998-02-19 20:58:44 +00:00
parent bd36dbaaa5
commit 05f9dce34f
1 changed files with 31 additions and 69 deletions

View File

@ -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);
} }