summaryrefslogtreecommitdiffstats
path: root/Include/internal/pycore_pythread.h
diff options
context:
space:
mode:
authorJeremy Maitin-Shepard <jeremy@jeremyms.com>2024-10-02 16:17:49 (GMT)
committerGitHub <noreply@github.com>2024-10-02 16:17:49 (GMT)
commit8cc5aa47ee464ddfd8da5461edecf4a5c72df2ff (patch)
tree41cdda0e2be153a4363cec9d616856444b306273 /Include/internal/pycore_pythread.h
parent113b2d7583cdbf79da18e696f299a9aca24b599b (diff)
downloadcpython-8cc5aa47ee464ddfd8da5461edecf4a5c72df2ff.zip
cpython-8cc5aa47ee464ddfd8da5461edecf4a5c72df2ff.tar.gz
cpython-8cc5aa47ee464ddfd8da5461edecf4a5c72df2ff.tar.bz2
gh-87135: Hang non-main threads that attempt to acquire the GIL during finalization (GH-105805)
Instead of surprise crashes and memory corruption, we now hang threads that attempt to re-enter the Python interpreter after Python runtime finalization has started. These are typically daemon threads (our long standing mis-feature) but could also be threads spawned by extension modules that then try to call into Python. This marks the `PyThread_exit_thread` public C API as deprecated as there is no plausible safe way to accomplish that on any supported platform in the face of things like C++ code with finalizers anywhere on a thread's stack. Doing this was the least bad option. Co-authored-by: Gregory P. Smith <greg@krypto.org>
Diffstat (limited to 'Include/internal/pycore_pythread.h')
-rw-r--r--Include/internal/pycore_pythread.h13
1 files changed, 13 insertions, 0 deletions
diff --git a/Include/internal/pycore_pythread.h b/Include/internal/pycore_pythread.h
index f3f5942..a1e084c 100644
--- a/Include/internal/pycore_pythread.h
+++ b/Include/internal/pycore_pythread.h
@@ -152,6 +152,19 @@ PyAPI_FUNC(int) PyThread_join_thread(PyThread_handle_t);
* a non-zero value on failure.
*/
PyAPI_FUNC(int) PyThread_detach_thread(PyThread_handle_t);
+/*
+ * Hangs the thread indefinitely without exiting it.
+ *
+ * gh-87135: There is no safe way to exit a thread other than returning
+ * normally from its start function. This is used during finalization in lieu
+ * of actually exiting the thread. Since the program is expected to terminate
+ * soon anyway, it does not matter if the thread stack stays around until then.
+ *
+ * This is unfortunate for embedders who may not be terminating their process
+ * when they're done with the interpreter, but our C API design does not allow
+ * for safely exiting threads attempting to re-enter Python post finalization.
+ */
+void _Py_NO_RETURN PyThread_hang_thread(void);
#ifdef __cplusplus
}