This issue tracker has been migrated to GitHub, and is currently read-only.
For more information, see the GitHub FAQs in the Python's Developer Guide.

Author neologix
Recipients Albert.Zeyer, neologix, pitrou, r.david.murray
Date 2013-02-23.10:30:27
SpamBayes Score -1.0
Marked as misclassified Yes
Message-id <1361615427.87.0.143435445319.issue17263@psf.upfronthosting.co.za>
In-reply-to
Content
Alright, here's what's going on.
When the main thread exits, it triggers the interpreter shutdown, which clears all the tstates in PyInterpreterState_Clear():
"""
void
PyInterpreterState_Clear(PyInterpreterState *interp)
{
    PyThreadState *p;
    HEAD_LOCK();
    for (p = interp->tstate_head; p != NULL; p = p->next)
        PyThreadState_Clear(p);
"""

PyThreadState_Clear() clears the TLS dict:
"""
void
PyThreadState_Clear(PyThreadState *tstate)
{
    if (Py_VerboseFlag && tstate->frame != NULL)
        fprintf(stderr,
          "PyThreadState_Clear: warning: thread still has a frame\n");

    Py_CLEAR(tstate->frame);

    Py_CLEAR(tstate->dict);
"""

This deallocation of the TLS dict But when the TLS object is deallocated, if it releases the GIL, this can make other threads runnable, while the interpreter is shutting down (and the tstate are in an unusable state), so all  bets are off. Note that this can only happen if there are daemon threads, which is the case in your testcase.

Basically, the problem is that arbitrary code can be run while the interpreter is shutting down because of the TLS deallocation.

I'm not sure about how to handle it, but one possibility to limit such problems would be to not deallocate the tstate if a thread is currently still active:

"""
diff --git a/Python/pystate.c b/Python/pystate.c
--- a/Python/pystate.c
+++ b/Python/pystate.c
@@ -230,9 +230,12 @@
 void
 PyThreadState_Clear(PyThreadState *tstate)
 {
-    if (Py_VerboseFlag && tstate->frame != NULL)
-        fprintf(stderr,
-          "PyThreadState_Clear: warning: thread still has a frame\n");
+    if (tstate->frame != NULL) {
+        if (Py_VerboseFlag)
+            fprintf(stderr,
+                    "PyThreadState_Clear: warning: thread still has a frame\n");
+        return;
+    }
 
     Py_CLEAR(tstate->frame);
 
"""

But this would leak to memory leak in some cases...
History
Date User Action Args
2013-02-23 10:30:27neologixsetrecipients: + neologix, pitrou, r.david.murray, Albert.Zeyer
2013-02-23 10:30:27neologixsetmessageid: <1361615427.87.0.143435445319.issue17263@psf.upfronthosting.co.za>
2013-02-23 10:30:27neologixlinkissue17263 messages
2013-02-23 10:30:27neologixcreate