summaryrefslogtreecommitdiff
path: root/Programs
diff options
context:
space:
mode:
authorVictor Stinner <victor.stinner@gmail.com>2017-11-30 22:05:00 +0100
committerGitHub <noreply@github.com>2017-11-30 22:05:00 +0100
commitb4d1e1f7c1af6ae33f0e371576c8bcafedb099db (patch)
tree857873eca2c22a51524b53fb54e30ea9f66f66d7 /Programs
parent986375ebde0dd5ff2b7349e445a06bd28a3a8ee2 (diff)
downloadcpython-git-b4d1e1f7c1af6ae33f0e371576c8bcafedb099db.tar.gz
bpo-20891: Fix PyGILState_Ensure() (#4650)
When PyGILState_Ensure() is called in a non-Python thread before PyEval_InitThreads(), only call PyEval_InitThreads() after calling PyThreadState_New() to fix a crash. Add an unit test in test_embed.
Diffstat (limited to 'Programs')
-rw-r--r--Programs/_testembed.c49
1 files changed, 49 insertions, 0 deletions
diff --git a/Programs/_testembed.c b/Programs/_testembed.c
index 21aa76e9de..a528f3e3aa 100644
--- a/Programs/_testembed.c
+++ b/Programs/_testembed.c
@@ -1,4 +1,5 @@
#include <Python.h>
+#include "pythread.h"
#include <inttypes.h>
#include <stdio.h>
@@ -147,6 +148,53 @@ static int test_pre_initialization_api(void)
return 0;
}
+static void bpo20891_thread(void *lockp)
+{
+ PyThread_type_lock lock = *((PyThread_type_lock*)lockp);
+
+ PyGILState_STATE state = PyGILState_Ensure();
+ if (!PyGILState_Check()) {
+ fprintf(stderr, "PyGILState_Check failed!");
+ abort();
+ }
+
+ PyGILState_Release(state);
+
+ PyThread_release_lock(lock);
+
+ PyThread_exit_thread();
+}
+
+static int test_bpo20891(void)
+{
+ /* bpo-20891: Calling PyGILState_Ensure in a non-Python thread before
+ calling PyEval_InitThreads() must not crash. PyGILState_Ensure() must
+ call PyEval_InitThreads() for us in this case. */
+ PyThread_type_lock lock = PyThread_allocate_lock();
+ if (!lock) {
+ fprintf(stderr, "PyThread_allocate_lock failed!");
+ return 1;
+ }
+
+ _testembed_Py_Initialize();
+
+ unsigned long thrd = PyThread_start_new_thread(bpo20891_thread, &lock);
+ if (thrd == PYTHREAD_INVALID_THREAD_ID) {
+ fprintf(stderr, "PyThread_start_new_thread failed!");
+ return 1;
+ }
+ PyThread_acquire_lock(lock, WAIT_LOCK);
+
+ Py_BEGIN_ALLOW_THREADS
+ /* wait until the thread exit */
+ PyThread_acquire_lock(lock, WAIT_LOCK);
+ Py_END_ALLOW_THREADS
+
+ PyThread_free_lock(lock);
+
+ return 0;
+}
+
/* *********************************************************
* List of test cases and the function that implements it.
@@ -170,6 +218,7 @@ static struct TestCase TestCases[] = {
{ "forced_io_encoding", test_forced_io_encoding },
{ "repeated_init_and_subinterpreters", test_repeated_init_and_subinterpreters },
{ "pre_initialization_api", test_pre_initialization_api },
+ { "bpo20891", test_bpo20891 },
{ NULL, NULL }
};