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)

147148

return 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