bpo-20891: Fix PyGILState_Ensure() (#4650) (#4655) · python/cpython@e10c9de (original) (raw)

1

1

`#include <Python.h>

`

``

2

`+

#include "pythread.h"

`

2

3

`#include <stdio.h>

`

3

4

``

4

5

`/*********************************************************

`

`@@ -33,7 +34,7 @@ static void print_subinterp(void)

`

33

34

` );

`

34

35

`}

`

35

36

``

36

``

`-

static void test_repeated_init_and_subinterpreters(void)

`

``

37

`+

static int test_repeated_init_and_subinterpreters(void)

`

37

38

`{

`

38

39

`PyThreadState *mainstate, *substate;

`

39

40

`#ifdef WITH_THREAD

`

`@@ -70,6 +71,7 @@ static void test_repeated_init_and_subinterpreters(void)

`

70

71

`PyEval_RestoreThread(mainstate);

`

71

72

`Py_Finalize();

`

72

73

` }

`

``

74

`+

return 0;

`

73

75

`}

`

74

76

``

75

77

`/*****************************************************

`

`@@ -103,7 +105,7 @@ static void check_stdio_details(const char *encoding, const char * errors)

`

103

105

`Py_Finalize();

`

104

106

`}

`

105

107

``

106

``

`-

static void test_forced_io_encoding(void)

`

``

108

`+

static int test_forced_io_encoding(void)

`

107

109

`{

`

108

110

`/* Check various combinations */

`

109

111

`printf("--- Use defaults ---\n");

`

`@@ -122,19 +124,123 @@ static void test_forced_io_encoding(void)

`

122

124

`printf("Unexpected success calling Py_SetStandardStreamEncoding");

`

123

125

` }

`

124

126

`Py_Finalize();

`

``

127

`+

return 0;

`

125

128

`}

`

126

129

``

127

``

`-

/* Different embedding tests */

`

128

``

`-

int main(int argc, char *argv[])

`

``

130

+

``

131

`+

/*********************************************************

`

``

132

`+

`

``

133

`+

*********************************************************/

`

``

134

+

``

135

`+

static int test_pre_initialization_api(void)

`

129

136

`{

`

``

137

`+

/* Leading "./" ensures getpath.c can still find the standard library */

`

``

138

`+

wchar_t *program = Py_DecodeLocale("./spam", NULL);

`

``

139

`+

if (program == NULL) {

`

``

140

`+

fprintf(stderr, "Fatal error: cannot decode program name\n");

`

``

141

`+

return 1;

`

``

142

`+

}

`

``

143

`+

Py_SetProgramName(program);

`

130

144

``

131

``

`-

/* TODO: Check the argument string to allow for more test cases */

`

132

``

`-

if (argc > 1) {

`

133

``

`-

/* For now: assume "forced_io_encoding */

`

134

``

`-

test_forced_io_encoding();

`

135

``

`-

} else {

`

136

``

`-

/* Run the original embedding test case by default */

`

137

``

`-

test_repeated_init_and_subinterpreters();

`

``

145

`+

Py_Initialize();

`

``

146

`+

Py_Finalize();

`

``

147

+

``

148

`+

PyMem_RawFree(program);

`

``

149

`+

return 0;

`

``

150

`+

}

`

``

151

+

``

152

`+

static void bpo20891_thread(void *lockp)

`

``

153

`+

{

`

``

154

`+

PyThread_type_lock lock = ((PyThread_type_lock)lockp);

`

``

155

+

``

156

`+

PyGILState_STATE state = PyGILState_Ensure();

`

``

157

`+

if (!PyGILState_Check()) {

`

``

158

`+

fprintf(stderr, "PyGILState_Check failed!");

`

``

159

`+

abort();

`

``

160

`+

}

`

``

161

+

``

162

`+

PyGILState_Release(state);

`

``

163

+

``

164

`+

PyThread_release_lock(lock);

`

``

165

+

``

166

`+

PyThread_exit_thread();

`

``

167

`+

}

`

``

168

+

``

169

`+

static int test_bpo20891(void)

`

``

170

`+

{

`

``

171

`+

/* bpo-20891: Calling PyGILState_Ensure in a non-Python thread before

`

``

172

`+

calling PyEval_InitThreads() must not crash. PyGILState_Ensure() must

`

``

173

`+

call PyEval_InitThreads() for us in this case. */

`

``

174

`+

PyThread_type_lock lock = PyThread_allocate_lock();

`

``

175

`+

if (!lock) {

`

``

176

`+

fprintf(stderr, "PyThread_allocate_lock failed!");

`

``

177

`+

return 1;

`

``

178

`+

}

`

``

179

+

``

180

`+

_testembed_Py_Initialize();

`

``

181

+

``

182

`+

long thrd = PyThread_start_new_thread(bpo20891_thread, &lock);

`

``

183

`+

if (thrd == -1) {

`

``

184

`+

fprintf(stderr, "PyThread_start_new_thread failed!");

`

``

185

`+

return 1;

`

138

186

` }

`

``

187

`+

PyThread_acquire_lock(lock, WAIT_LOCK);

`

``

188

+

``

189

`+

Py_BEGIN_ALLOW_THREADS

`

``

190

`+

/* wait until the thread exit */

`

``

191

`+

PyThread_acquire_lock(lock, WAIT_LOCK);

`

``

192

`+

Py_END_ALLOW_THREADS

`

``

193

+

``

194

`+

PyThread_free_lock(lock);

`

``

195

+

139

196

`return 0;

`

140

197

`}

`

``

198

+

``

199

+

``

200

`+

/* *********************************************************

`

``

201

`+

`

``

202

`+

`

``

203

`+

`

``

204

`+

`

``

205

`+

`

``

206

`+

`

``

207

`+

`

``

208

`+

`

``

209

`+

`

``

210

`+

`

``

211

`+

*********************************************************/

`

``

212

`+

struct TestCase

`

``

213

`+

{

`

``

214

`+

const char *name;

`

``

215

`+

int (*func)(void);

`

``

216

`+

};

`

``

217

+

``

218

`+

static struct TestCase TestCases[] = {

`

``

219

`+

{ "forced_io_encoding", test_forced_io_encoding },

`

``

220

`+

{ "repeated_init_and_subinterpreters", test_repeated_init_and_subinterpreters },

`

``

221

`+

{ "pre_initialization_api", test_pre_initialization_api },

`

``

222

`+

{ "bpo20891", test_bpo20891 },

`

``

223

`+

{ NULL, NULL }

`

``

224

`+

};

`

``

225

+

``

226

`+

int main(int argc, char *argv[])

`

``

227

`+

{

`

``

228

`+

if (argc > 1) {

`

``

229

`+

for (struct TestCase *tc = TestCases; tc && tc->name; tc++) {

`

``

230

`+

if (strcmp(argv[1], tc->name) == 0)

`

``

231

`+

return (*tc->func)();

`

``

232

`+

}

`

``

233

`+

}

`

``

234

+

``

235

`+

/* No match found, or no test name provided, so display usage */

`

``

236

`+

printf("Python " PY_VERSION " _testembed executable for embedded interpreter tests\n"

`

``

237

`+

"Normally executed via 'EmbeddingTests' in Lib/test/test_capi.py\n\n"

`

``

238

`+

"Usage: %s TESTNAME\n\nAll available tests:\n", argv[0]);

`

``

239

`+

for (struct TestCase *tc = TestCases; tc && tc->name; tc++) {

`

``

240

`+

printf(" %s\n", tc->name);

`

``

241

`+

}

`

``

242

+

``

243

`+

/* Non-zero exit code will cause test_capi.py tests to fail.

`

``

244

`+

This is intentional. */

`

``

245

`+

return -1;

`

``

246

`+

}

`