From 032215451bd9a8fc3a068e8a77871277e0f162d8 Mon Sep 17 00:00:00 2001 From: Georg Brandl Date: Tue, 12 Aug 2008 08:46:02 +0000 Subject: [PATCH] Backport r60148 and r65481: sanity checks to avoid infinite loops. --- Python/pystate.c | 14 ++++++++++++++ Python/thread.c | 12 +++++++++++- 2 files changed, 25 insertions(+), 1 deletion(-) diff --git a/Python/pystate.c b/Python/pystate.c index 086789d355..da417c1032 100644 --- a/Python/pystate.c +++ b/Python/pystate.c @@ -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(); diff --git a/Python/thread.c b/Python/thread.c index 3a2c7af6ff..be4d092bcc 100644 --- a/Python/thread.c +++ b/Python/thread.c @@ -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); -- 2.40.0