diff options
author | Victor Stinner <victor.stinner@gmail.com> | 2017-11-30 21:05:00 (GMT) |
---|---|---|
committer | GitHub <noreply@github.com> | 2017-11-30 21:05:00 (GMT) |
commit | b4d1e1f7c1af6ae33f0e371576c8bcafedb099db (patch) | |
tree | 857873eca2c22a51524b53fb54e30ea9f66f66d7 /Programs/_testembed.c | |
parent | 986375ebde0dd5ff2b7349e445a06bd28a3a8ee2 (diff) | |
download | cpython-b4d1e1f7c1af6ae33f0e371576c8bcafedb099db.zip cpython-b4d1e1f7c1af6ae33f0e371576c8bcafedb099db.tar.gz cpython-b4d1e1f7c1af6ae33f0e371576c8bcafedb099db.tar.bz2 |
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/_testembed.c')
-rw-r--r-- | Programs/_testembed.c | 49 |
1 files changed, 49 insertions, 0 deletions
diff --git a/Programs/_testembed.c b/Programs/_testembed.c index 21aa76e..a528f3e 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 } }; |