]> granicus.if.org Git - python/commitdiff
Backport r60148 and r65481: sanity checks to avoid infinite loops.
authorGeorg Brandl <georg@python.org>
Tue, 12 Aug 2008 08:46:02 +0000 (08:46 +0000)
committerGeorg Brandl <georg@python.org>
Tue, 12 Aug 2008 08:46:02 +0000 (08:46 +0000)
Python/pystate.c
Python/thread.c

index 086789d3553cc909cd70fe60a880c4611153300e..da417c103202f792fefd42ea3fcb617ceb36585c 100644 (file)
@@ -240,6 +240,7 @@ tstate_delete_common(PyThreadState *tstate)
 {
        PyInterpreterState *interp;
        PyThreadState **p;
+       PyThreadState *prev_p = NULL;
        if (tstate == NULL)
                Py_FatalError("PyThreadState_Delete: NULL tstate");
        interp = tstate->interp;
@@ -252,6 +253,19 @@ tstate_delete_common(PyThreadState *tstate)
                                "PyThreadState_Delete: invalid tstate");
                if (*p == tstate)
                        break;
+               /* Sanity check.  These states should never happen but if
+                * they do we must abort.  Otherwise we'll end up spinning in
+                * in a tight loop with the lock held.  A similar check is done
+                * in thread.c find_key().  */
+               if (*p == prev_p)
+                       Py_FatalError(
+                               "PyThreadState_Delete: small circular list(!)"
+                                " and tstate not found.");
+               prev_p = *p;
+               if ((*p)->next == interp->tstate_head)
+                       Py_FatalError(
+                               "PyThreadState_Delete: circular list(!) and"
+                                " tstate not found.");
        }
        *p = tstate->next;
        HEAD_UNLOCK();
index 3a2c7af6ff6f05501dbba7ef9369b8af70ea9cd8..be4d092bccda88933001eeffa3cd4d0e1f3c3f7f 100644 (file)
@@ -264,15 +264,25 @@ static int nkeys = 0;  /* PyThread_create_key() hands out nkeys+1 next */
 static struct key *
 find_key(int key, void *value)
 {
-       struct key *p;
+       struct key *p, *prev_p;
        long id = PyThread_get_thread_ident();
 
        if (!keymutex)
                return NULL;
        PyThread_acquire_lock(keymutex, 1);
+       prev_p = NULL;
        for (p = keyhead; p != NULL; p = p->next) {
                if (p->id == id && p->key == key)
                        goto Done;
+               /* Sanity check.  These states should never happen but if
+                * they do we must abort.  Otherwise we'll end up spinning in
+                * in a tight loop with the lock held.  A similar check is done
+                * in pystate.c tstate_delete_common().  */
+               if (p == prev_p)
+                       Py_FatalError("tls find_key: small circular list(!)");
+               prev_p = p;
+               if (p->next == keyhead)
+                       Py_FatalError("tls find_key: circular list(!)");
        }
        if (value == NULL) {
                assert(p == NULL);