@@ -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
158174void
159175PyImport_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