bpo-20891: Fix PyGILState_Ensure() (#4650) · python/cpython@b4d1e1f
11#include <Python.h>
2+#include "pythread.h"
23#include <inttypes.h>
34#include <stdio.h>
45@@ -147,6 +148,53 @@ static int test_pre_initialization_api(void)
147148return 0;
148149}
149150151+static void bpo20891_thread(void *lockp)
152+{
153+PyThread_type_lock lock = *((PyThread_type_lock*)lockp);
154+155+PyGILState_STATE state = PyGILState_Ensure();
156+if (!PyGILState_Check()) {
157+fprintf(stderr, "PyGILState_Check failed!");
158+abort();
159+ }
160+161+PyGILState_Release(state);
162+163+PyThread_release_lock(lock);
164+165+PyThread_exit_thread();
166+}
167+168+static int test_bpo20891(void)
169+{
170+/* bpo-20891: Calling PyGILState_Ensure in a non-Python thread before
171+ calling PyEval_InitThreads() must not crash. PyGILState_Ensure() must
172+ call PyEval_InitThreads() for us in this case. */
173+PyThread_type_lock lock = PyThread_allocate_lock();
174+if (!lock) {
175+fprintf(stderr, "PyThread_allocate_lock failed!");
176+return 1;
177+ }
178+179+_testembed_Py_Initialize();
180+181+unsigned long thrd = PyThread_start_new_thread(bpo20891_thread, &lock);
182+if (thrd == PYTHREAD_INVALID_THREAD_ID) {
183+fprintf(stderr, "PyThread_start_new_thread failed!");
184+return 1;
185+ }
186+PyThread_acquire_lock(lock, WAIT_LOCK);
187+188+Py_BEGIN_ALLOW_THREADS
189+/* wait until the thread exit */
190+PyThread_acquire_lock(lock, WAIT_LOCK);
191+Py_END_ALLOW_THREADS
192+193+PyThread_free_lock(lock);
194+195+return 0;
196+}
197+150198151199/* *********************************************************
152200 * List of test cases and the function that implements it.
@@ -170,6 +218,7 @@ static struct TestCase TestCases[] = {
170218 { "forced_io_encoding", test_forced_io_encoding },
171219 { "repeated_init_and_subinterpreters", test_repeated_init_and_subinterpreters },
172220 { "pre_initialization_api", test_pre_initialization_api },
221+ { "bpo20891", test_bpo20891 },
173222 { NULL, NULL }
174223};
175224