Skip to content

Commit b2566d8

Browse files
authored
GH-113633: Use module state structure for _testcapi. (GH-113634)
Use module state structure for _testcapi.
1 parent 8e4ff5c commit b2566d8

File tree

2 files changed

+65
-51
lines changed

2 files changed

+65
-51
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Use module state for the _testcapi extension module.

Modules/_testcapimodule.c

+64-51
Original file line numberDiff line numberDiff line change
@@ -33,15 +33,32 @@
3333

3434
// Forward declarations
3535
static struct PyModuleDef _testcapimodule;
36-
static PyObject *TestError; /* set to exception object in init */
3736

37+
// Module state
38+
typedef struct {
39+
PyObject *error; // _testcapi.error object
40+
} testcapistate_t;
41+
42+
static testcapistate_t*
43+
get_testcapi_state(PyObject *module)
44+
{
45+
void *state = PyModule_GetState(module);
46+
assert(state != NULL);
47+
return (testcapistate_t *)state;
48+
}
3849

39-
/* Raise TestError with test_name + ": " + msg, and return NULL. */
50+
static PyObject *
51+
get_testerror(PyObject *self) {
52+
testcapistate_t *state = get_testcapi_state((PyObject *)Py_TYPE(self));
53+
return state->error;
54+
}
55+
56+
/* Raise _testcapi.error with test_name + ": " + msg, and return NULL. */
4057

4158
static PyObject *
42-
raiseTestError(const char* test_name, const char* msg)
59+
raiseTestError(PyObject *self, const char* test_name, const char* msg)
4360
{
44-
PyErr_Format(TestError, "%s: %s", test_name, msg);
61+
PyErr_Format(get_testerror(self), "%s: %s", test_name, msg);
4562
return NULL;
4663
}
4764

@@ -52,10 +69,10 @@ raiseTestError(const char* test_name, const char* msg)
5269
platforms have these hardcoded. Better safe than sorry.
5370
*/
5471
static PyObject*
55-
sizeof_error(const char* fatname, const char* typname,
72+
sizeof_error(PyObject *self, const char* fatname, const char* typname,
5673
int expected, int got)
5774
{
58-
PyErr_Format(TestError,
75+
PyErr_Format(get_testerror(self),
5976
"%s #define == %d but sizeof(%s) == %d",
6077
fatname, expected, typname, got);
6178
return (PyObject*)NULL;
@@ -66,7 +83,7 @@ test_config(PyObject *self, PyObject *Py_UNUSED(ignored))
6683
{
6784
#define CHECK_SIZEOF(FATNAME, TYPE) \
6885
if (FATNAME != sizeof(TYPE)) \
69-
return sizeof_error(#FATNAME, #TYPE, FATNAME, sizeof(TYPE))
86+
return sizeof_error(self, #FATNAME, #TYPE, FATNAME, sizeof(TYPE))
7087

7188
CHECK_SIZEOF(SIZEOF_SHORT, short);
7289
CHECK_SIZEOF(SIZEOF_INT, int);
@@ -89,15 +106,15 @@ test_sizeof_c_types(PyObject *self, PyObject *Py_UNUSED(ignored))
89106
#endif
90107
#define CHECK_SIZEOF(TYPE, EXPECTED) \
91108
if (EXPECTED != sizeof(TYPE)) { \
92-
PyErr_Format(TestError, \
109+
PyErr_Format(get_testerror(self), \
93110
"sizeof(%s) = %u instead of %u", \
94111
#TYPE, sizeof(TYPE), EXPECTED); \
95112
return (PyObject*)NULL; \
96113
}
97114
#define IS_SIGNED(TYPE) (((TYPE)-1) < (TYPE)0)
98115
#define CHECK_SIGNNESS(TYPE, SIGNED) \
99116
if (IS_SIGNED(TYPE) != SIGNED) { \
100-
PyErr_Format(TestError, \
117+
PyErr_Format(get_testerror(self), \
101118
"%s signness is, instead of %i", \
102119
#TYPE, IS_SIGNED(TYPE), SIGNED); \
103120
return (PyObject*)NULL; \
@@ -170,7 +187,7 @@ test_list_api(PyObject *self, PyObject *Py_UNUSED(ignored))
170187
for (i = 0; i < NLIST; ++i) {
171188
PyObject* anint = PyList_GET_ITEM(list, i);
172189
if (PyLong_AS_LONG(anint) != NLIST-1-i) {
173-
PyErr_SetString(TestError,
190+
PyErr_SetString(get_testerror(self),
174191
"test_list_api: reverse screwed up");
175192
Py_DECREF(list);
176193
return (PyObject*)NULL;
@@ -183,7 +200,7 @@ test_list_api(PyObject *self, PyObject *Py_UNUSED(ignored))
183200
}
184201

185202
static int
186-
test_dict_inner(int count)
203+
test_dict_inner(PyObject *self, int count)
187204
{
188205
Py_ssize_t pos = 0, iterations = 0;
189206
int i;
@@ -231,7 +248,7 @@ test_dict_inner(int count)
231248

232249
if (iterations != count) {
233250
PyErr_SetString(
234-
TestError,
251+
get_testerror(self),
235252
"test_dict_iteration: dict iteration went wrong ");
236253
return -1;
237254
} else {
@@ -250,7 +267,7 @@ test_dict_iteration(PyObject* self, PyObject *Py_UNUSED(ignored))
250267
int i;
251268

252269
for (i = 0; i < 200; i++) {
253-
if (test_dict_inner(i) < 0) {
270+
if (test_dict_inner(self, i) < 0) {
254271
return NULL;
255272
}
256273
}
@@ -334,14 +351,14 @@ test_lazy_hash_inheritance(PyObject* self, PyObject *Py_UNUSED(ignored))
334351
if (obj == NULL) {
335352
PyErr_Clear();
336353
PyErr_SetString(
337-
TestError,
354+
get_testerror(self),
338355
"test_lazy_hash_inheritance: failed to create object");
339356
return NULL;
340357
}
341358

342359
if (type->tp_dict != NULL) {
343360
PyErr_SetString(
344-
TestError,
361+
get_testerror(self),
345362
"test_lazy_hash_inheritance: type initialised too soon");
346363
Py_DECREF(obj);
347364
return NULL;
@@ -351,23 +368,23 @@ test_lazy_hash_inheritance(PyObject* self, PyObject *Py_UNUSED(ignored))
351368
if ((hash == -1) && PyErr_Occurred()) {
352369
PyErr_Clear();
353370
PyErr_SetString(
354-
TestError,
371+
get_testerror(self),
355372
"test_lazy_hash_inheritance: could not hash object");
356373
Py_DECREF(obj);
357374
return NULL;
358375
}
359376

360377
if (type->tp_dict == NULL) {
361378
PyErr_SetString(
362-
TestError,
379+
get_testerror(self),
363380
"test_lazy_hash_inheritance: type not initialised by hash()");
364381
Py_DECREF(obj);
365382
return NULL;
366383
}
367384

368385
if (type->tp_hash != PyType_Type.tp_hash) {
369386
PyErr_SetString(
370-
TestError,
387+
get_testerror(self),
371388
"test_lazy_hash_inheritance: unexpected hash function");
372389
Py_DECREF(obj);
373390
return NULL;
@@ -427,7 +444,7 @@ py_buildvalue_ints(PyObject *self, PyObject *args)
427444
}
428445

429446
static int
430-
test_buildvalue_N_error(const char *fmt)
447+
test_buildvalue_N_error(PyObject *self, const char *fmt)
431448
{
432449
PyObject *arg, *res;
433450

@@ -443,7 +460,7 @@ test_buildvalue_N_error(const char *fmt)
443460
}
444461
Py_DECREF(res);
445462
if (Py_REFCNT(arg) != 1) {
446-
PyErr_Format(TestError, "test_buildvalue_N: "
463+
PyErr_Format(get_testerror(self), "test_buildvalue_N: "
447464
"arg was not decrefed in successful "
448465
"Py_BuildValue(\"%s\")", fmt);
449466
return -1;
@@ -452,13 +469,13 @@ test_buildvalue_N_error(const char *fmt)
452469
Py_INCREF(arg);
453470
res = Py_BuildValue(fmt, raise_error, NULL, arg);
454471
if (res != NULL || !PyErr_Occurred()) {
455-
PyErr_Format(TestError, "test_buildvalue_N: "
472+
PyErr_Format(get_testerror(self), "test_buildvalue_N: "
456473
"Py_BuildValue(\"%s\") didn't complain", fmt);
457474
return -1;
458475
}
459476
PyErr_Clear();
460477
if (Py_REFCNT(arg) != 1) {
461-
PyErr_Format(TestError, "test_buildvalue_N: "
478+
PyErr_Format(get_testerror(self), "test_buildvalue_N: "
462479
"arg was not decrefed in failed "
463480
"Py_BuildValue(\"%s\")", fmt);
464481
return -1;
@@ -482,25 +499,25 @@ test_buildvalue_N(PyObject *self, PyObject *Py_UNUSED(ignored))
482499
return NULL;
483500
}
484501
if (res != arg) {
485-
return raiseTestError("test_buildvalue_N",
502+
return raiseTestError(self, "test_buildvalue_N",
486503
"Py_BuildValue(\"N\") returned wrong result");
487504
}
488505
if (Py_REFCNT(arg) != 2) {
489-
return raiseTestError("test_buildvalue_N",
506+
return raiseTestError(self, "test_buildvalue_N",
490507
"arg was not decrefed in Py_BuildValue(\"N\")");
491508
}
492509
Py_DECREF(res);
493510
Py_DECREF(arg);
494511

495-
if (test_buildvalue_N_error("O&N") < 0)
512+
if (test_buildvalue_N_error(self, "O&N") < 0)
496513
return NULL;
497-
if (test_buildvalue_N_error("(O&N)") < 0)
514+
if (test_buildvalue_N_error(self, "(O&N)") < 0)
498515
return NULL;
499-
if (test_buildvalue_N_error("[O&N]") < 0)
516+
if (test_buildvalue_N_error(self, "[O&N]") < 0)
500517
return NULL;
501-
if (test_buildvalue_N_error("{O&N}") < 0)
518+
if (test_buildvalue_N_error(self, "{O&N}") < 0)
502519
return NULL;
503-
if (test_buildvalue_N_error("{()O&(())N}") < 0)
520+
if (test_buildvalue_N_error(self, "{()O&(())N}") < 0)
504521
return NULL;
505522

506523
Py_RETURN_NONE;
@@ -910,7 +927,7 @@ test_string_to_double(PyObject *self, PyObject *Py_UNUSED(ignored)) {
910927

911928
Py_RETURN_NONE;
912929
fail:
913-
return raiseTestError("test_string_to_double", msg);
930+
return raiseTestError(self, "test_string_to_double", msg);
914931
#undef CHECK_STRING
915932
#undef CHECK_INVALID
916933
}
@@ -1061,7 +1078,7 @@ test_capsule(PyObject *self, PyObject *Py_UNUSED(ignored))
10611078

10621079
exit:
10631080
if (error) {
1064-
return raiseTestError("test_capsule", error);
1081+
return raiseTestError(self, "test_capsule", error);
10651082
}
10661083
Py_RETURN_NONE;
10671084
#undef FAIL
@@ -1272,7 +1289,7 @@ test_from_contiguous(PyObject* self, PyObject *Py_UNUSED(ignored))
12721289
ptr = view.buf;
12731290
for (i = 0; i < 5; i++) {
12741291
if (ptr[2*i] != i) {
1275-
PyErr_SetString(TestError,
1292+
PyErr_SetString(get_testerror(self),
12761293
"test_from_contiguous: incorrect result");
12771294
return NULL;
12781295
}
@@ -1285,7 +1302,7 @@ test_from_contiguous(PyObject* self, PyObject *Py_UNUSED(ignored))
12851302
ptr = view.buf;
12861303
for (i = 0; i < 5; i++) {
12871304
if (*(ptr-2*i) != i) {
1288-
PyErr_SetString(TestError,
1305+
PyErr_SetString(get_testerror(self),
12891306
"test_from_contiguous: incorrect result");
12901307
return NULL;
12911308
}
@@ -1338,7 +1355,7 @@ test_pep3118_obsolete_write_locks(PyObject* self, PyObject *Py_UNUSED(ignored))
13381355
Py_RETURN_NONE;
13391356

13401357
error:
1341-
PyErr_SetString(TestError,
1358+
PyErr_SetString(get_testerror(self),
13421359
"test_pep3118_obsolete_write_locks: failure");
13431360
return NULL;
13441361
}
@@ -1959,7 +1976,7 @@ test_pythread_tss_key_state(PyObject *self, PyObject *args)
19591976
{
19601977
Py_tss_t tss_key = Py_tss_NEEDS_INIT;
19611978
if (PyThread_tss_is_created(&tss_key)) {
1962-
return raiseTestError("test_pythread_tss_key_state",
1979+
return raiseTestError(self, "test_pythread_tss_key_state",
19631980
"TSS key not in an uninitialized state at "
19641981
"creation time");
19651982
}
@@ -1968,27 +1985,27 @@ test_pythread_tss_key_state(PyObject *self, PyObject *args)
19681985
return NULL;
19691986
}
19701987
if (!PyThread_tss_is_created(&tss_key)) {
1971-
return raiseTestError("test_pythread_tss_key_state",
1988+
return raiseTestError(self, "test_pythread_tss_key_state",
19721989
"PyThread_tss_create succeeded, "
19731990
"but with TSS key in an uninitialized state");
19741991
}
19751992
if (PyThread_tss_create(&tss_key) != 0) {
1976-
return raiseTestError("test_pythread_tss_key_state",
1993+
return raiseTestError(self, "test_pythread_tss_key_state",
19771994
"PyThread_tss_create unsuccessful with "
19781995
"an already initialized key");
19791996
}
19801997
#define CHECK_TSS_API(expr) \
19811998
(void)(expr); \
19821999
if (!PyThread_tss_is_created(&tss_key)) { \
1983-
return raiseTestError("test_pythread_tss_key_state", \
2000+
return raiseTestError(self, "test_pythread_tss_key_state", \
19842001
"TSS key initialization state was not " \
19852002
"preserved after calling " #expr); }
19862003
CHECK_TSS_API(PyThread_tss_set(&tss_key, NULL));
19872004
CHECK_TSS_API(PyThread_tss_get(&tss_key));
19882005
#undef CHECK_TSS_API
19892006
PyThread_tss_delete(&tss_key);
19902007
if (PyThread_tss_is_created(&tss_key)) {
1991-
return raiseTestError("test_pythread_tss_key_state",
2008+
return raiseTestError(self, "test_pythread_tss_key_state",
19922009
"PyThread_tss_delete called, but did not "
19932010
"set the key state to uninitialized");
19942011
}
@@ -1999,7 +2016,7 @@ test_pythread_tss_key_state(PyObject *self, PyObject *args)
19992016
return NULL;
20002017
}
20012018
if (PyThread_tss_is_created(ptr_key)) {
2002-
return raiseTestError("test_pythread_tss_key_state",
2019+
return raiseTestError(self, "test_pythread_tss_key_state",
20032020
"TSS key not in an uninitialized state at "
20042021
"allocation time");
20052022
}
@@ -3831,14 +3848,9 @@ static PyTypeObject ContainerNoGC_type = {
38313848

38323849
static struct PyModuleDef _testcapimodule = {
38333850
PyModuleDef_HEAD_INIT,
3834-
"_testcapi",
3835-
NULL,
3836-
-1,
3837-
TestMethods,
3838-
NULL,
3839-
NULL,
3840-
NULL,
3841-
NULL
3851+
.m_name = "_testcapi",
3852+
.m_size = sizeof(testcapistate_t),
3853+
.m_methods = TestMethods,
38423854
};
38433855

38443856
/* Per PEP 489, this module will not be converted to multi-phase initialization
@@ -3933,9 +3945,10 @@ PyInit__testcapi(void)
39333945
PyModule_AddIntConstant(m, "the_number_three", 3);
39343946
PyModule_AddIntMacro(m, Py_C_RECURSION_LIMIT);
39353947

3936-
TestError = PyErr_NewException("_testcapi.error", NULL, NULL);
3937-
Py_INCREF(TestError);
3938-
PyModule_AddObject(m, "error", TestError);
3948+
testcapistate_t *state = get_testcapi_state(m);
3949+
state->error = PyErr_NewException("_testcapi.error", NULL, NULL);
3950+
Py_INCREF(state->error);
3951+
PyModule_AddObject(m, "error", state->error);
39393952

39403953
if (PyType_Ready(&ContainerNoGC_type) < 0) {
39413954
return NULL;

0 commit comments

Comments
 (0)