Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 758eec0

Browse files
committed
Rewritten PyImport_Cleanup() and its helper, clear_carefully(). They
now implement the following finalization strategy. 1. Whenever this code deletes a module, its directory is cleared carefully, as follows: - set all names to None that begin with exactly one underscore - set all names to None that don't begin with two underscores - clear the directory 2. Modules are deleted in the following order: - modules with a reference count of 1, except __builtin__ or __sys__ - repeat until no more are found with a reference count of 1 - __main__ if it's still there - all remaining modules except __builtin__ or sys - sys _ __builtin__
1 parent 8095ebf commit 758eec0

1 file changed

Lines changed: 98 additions & 12 deletions

File tree

Python/import.c

Lines changed: 98 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -141,6 +141,9 @@ clear_carefully(d)
141141
int pos;
142142
PyObject *key, *value;
143143

144+
Py_INCREF(d); /* Prevent it from being deleted recursively */
145+
146+
/* First, clear only names starting with a single underscore */
144147
pos = 0;
145148
while (PyDict_Next(d, &pos, &key, &value)) {
146149
if (value != Py_None && PyString_Check(key)) {
@@ -149,31 +152,114 @@ clear_carefully(d)
149152
PyDict_SetItem(d, key, Py_None);
150153
}
151154
}
152-
153-
PyDict_Clear(d);
155+
156+
/* Next, clear all names except those starting with two underscores */
157+
pos = 0;
158+
while (PyDict_Next(d, &pos, &key, &value)) {
159+
if (value != Py_None && PyString_Check(key)) {
160+
char *s = PyString_AsString(key);
161+
if (s[0] != '_' || s[1] != '_')
162+
PyDict_SetItem(d, key, Py_None);
163+
}
164+
}
165+
166+
PyDict_Clear(d); /* Finally, clear all names */
167+
168+
Py_DECREF(d); /* Match INCREF at top */
154169
}
155170

171+
156172
/* Un-initialize things, as good as we can */
157173

158174
void
159175
PyImport_Cleanup()
160176
{
177+
int pos, ndone;
178+
char *name;
179+
PyObject *key, *value, *dict;
161180
PyInterpreterState *interp = PyThreadState_Get()->interp;
162-
PyObject *tmp = interp->modules;
163-
if (tmp != NULL) {
164-
int pos;
165-
PyObject *key, *value;
166-
interp->modules = NULL;
181+
PyObject *modules = interp->modules;
182+
183+
if (modules == NULL)
184+
return; /* Already done */
185+
186+
/* The special treatment of __builtin__ here is because even
187+
when it's not referenced as a module, its dictionary is
188+
referenced by almost every module's __builtins__. Since
189+
deleting a module clears its dictionary (even if there are
190+
references left to it), we need to delete the __builtin__
191+
module last. Likewise, we don't delete sys until the very
192+
end because it is implicitly referenced (e.g. by print).
193+
194+
Also note that we 'delete' modules by replacing their entry
195+
in the modules dict with None, rather than really deleting
196+
them; this avoids a rehash of the modules dictionary and
197+
also marks them as "non existent" so they won't be
198+
re-imported. */
199+
200+
/* First, repeatedly delete modules with a reference count of
201+
one (skipping __builtin__ and sys) and delete them */
202+
do {
203+
ndone = 0;
167204
pos = 0;
168-
while (PyDict_Next(tmp, &pos, &key, &value)) {
205+
while (PyDict_Next(modules, &pos, &key, &value)) {
206+
if (value->ob_refcnt != 1)
207+
continue;
169208
if (PyModule_Check(value)) {
170-
PyObject *d = PyModule_GetDict(value);
171-
clear_carefully(d);
209+
name = PyString_AsString(key);
210+
dict = PyModule_GetDict(value);
211+
if (strcmp(name, "__builtin__") == 0)
212+
continue;
213+
if (strcmp(name, "sys") == 0)
214+
continue;
215+
clear_carefully(dict);
216+
PyDict_SetItem(modules, key, Py_None);
217+
ndone++;
172218
}
173219
}
174-
PyDict_Clear(tmp);
175-
Py_DECREF(tmp);
220+
} while (ndone > 0);
221+
222+
/* Next, delete __main__ if it's still there */
223+
value = PyDict_GetItemString(modules, "__main__");
224+
if (value != NULL && PyModule_Check(value)) {
225+
dict = PyModule_GetDict(value);
226+
clear_carefully(dict);
227+
PyDict_SetItemString(modules, "__main__", Py_None);
176228
}
229+
230+
/* Next, delete all modules (still skipping __builtin__ and sys) */
231+
pos = 0;
232+
while (PyDict_Next(modules, &pos, &key, &value)) {
233+
if (PyModule_Check(value)) {
234+
name = PyString_AsString(key);
235+
dict = PyModule_GetDict(value);
236+
if (strcmp(name, "__builtin__") == 0)
237+
continue;
238+
if (strcmp(name, "sys") == 0)
239+
continue;
240+
clear_carefully(dict);
241+
PyDict_SetItem(modules, key, Py_None);
242+
}
243+
}
244+
245+
/* Next, delete sys and __builtin__ (in that order) */
246+
value = PyDict_GetItemString(modules, "sys");
247+
if (value != NULL && PyModule_Check(value)) {
248+
dict = PyModule_GetDict(value);
249+
clear_carefully(dict);
250+
PyDict_SetItemString(modules, "sys", Py_None);
251+
}
252+
value = PyDict_GetItemString(modules, "__builtin__");
253+
if (value != NULL && PyModule_Check(value)) {
254+
dict = PyModule_GetDict(value);
255+
clear_carefully(dict);
256+
PyDict_SetItemString(modules, "__builtin__", Py_None);
257+
}
258+
259+
/* Finally, clear and delete the modules directory */
260+
PyDict_Clear(modules);
261+
interp->modules = NULL;
262+
Py_DECREF(modules);
177263
}
178264

179265

0 commit comments

Comments
 (0)