summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorNeil Schemenauer <nas-github@arctrix.com>2024-01-01 23:04:09 (GMT)
committerGitHub <noreply@github.com>2024-01-01 23:04:09 (GMT)
commitb2566d89ce50e9924bb2fccb87dcfa3ceb6cc0d6 (patch)
tree2d8caa5bcc0754f8f4c103f73873db2bbd426ba2
parent8e4ff5c7885abb04a66d079499335c4d46106aff (diff)
downloadcpython-b2566d89ce50e9924bb2fccb87dcfa3ceb6cc0d6.zip
cpython-b2566d89ce50e9924bb2fccb87dcfa3ceb6cc0d6.tar.gz
cpython-b2566d89ce50e9924bb2fccb87dcfa3ceb6cc0d6.tar.bz2
GH-113633: Use module state structure for _testcapi. (GH-113634)
Use module state structure for _testcapi.
-rw-r--r--Misc/NEWS.d/next/Tests/2024-01-01-14-40-02.gh-issue-113633.VOY5ai.rst1
-rw-r--r--Modules/_testcapimodule.c115
2 files changed, 65 insertions, 51 deletions
diff --git a/Misc/NEWS.d/next/Tests/2024-01-01-14-40-02.gh-issue-113633.VOY5ai.rst b/Misc/NEWS.d/next/Tests/2024-01-01-14-40-02.gh-issue-113633.VOY5ai.rst
new file mode 100644
index 0000000..150c0d9
--- /dev/null
+++ b/Misc/NEWS.d/next/Tests/2024-01-01-14-40-02.gh-issue-113633.VOY5ai.rst
@@ -0,0 +1 @@
+Use module state for the _testcapi extension module.
diff --git a/Modules/_testcapimodule.c b/Modules/_testcapimodule.c
index 3527dfa..6762c61 100644
--- a/Modules/_testcapimodule.c
+++ b/Modules/_testcapimodule.c
@@ -33,15 +33,32 @@
// Forward declarations
static struct PyModuleDef _testcapimodule;
-static PyObject *TestError; /* set to exception object in init */
+// Module state
+typedef struct {
+ PyObject *error; // _testcapi.error object
+} testcapistate_t;
+
+static testcapistate_t*
+get_testcapi_state(PyObject *module)
+{
+ void *state = PyModule_GetState(module);
+ assert(state != NULL);
+ return (testcapistate_t *)state;
+}
-/* Raise TestError with test_name + ": " + msg, and return NULL. */
+static PyObject *
+get_testerror(PyObject *self) {
+ testcapistate_t *state = get_testcapi_state((PyObject *)Py_TYPE(self));
+ return state->error;
+}
+
+/* Raise _testcapi.error with test_name + ": " + msg, and return NULL. */
static PyObject *
-raiseTestError(const char* test_name, const char* msg)
+raiseTestError(PyObject *self, const char* test_name, const char* msg)
{
- PyErr_Format(TestError, "%s: %s", test_name, msg);
+ PyErr_Format(get_testerror(self), "%s: %s", test_name, msg);
return NULL;
}
@@ -52,10 +69,10 @@ raiseTestError(const char* test_name, const char* msg)
platforms have these hardcoded. Better safe than sorry.
*/
static PyObject*
-sizeof_error(const char* fatname, const char* typname,
+sizeof_error(PyObject *self, const char* fatname, const char* typname,
int expected, int got)
{
- PyErr_Format(TestError,
+ PyErr_Format(get_testerror(self),
"%s #define == %d but sizeof(%s) == %d",
fatname, expected, typname, got);
return (PyObject*)NULL;
@@ -66,7 +83,7 @@ test_config(PyObject *self, PyObject *Py_UNUSED(ignored))
{
#define CHECK_SIZEOF(FATNAME, TYPE) \
if (FATNAME != sizeof(TYPE)) \
- return sizeof_error(#FATNAME, #TYPE, FATNAME, sizeof(TYPE))
+ return sizeof_error(self, #FATNAME, #TYPE, FATNAME, sizeof(TYPE))
CHECK_SIZEOF(SIZEOF_SHORT, short);
CHECK_SIZEOF(SIZEOF_INT, int);
@@ -89,7 +106,7 @@ test_sizeof_c_types(PyObject *self, PyObject *Py_UNUSED(ignored))
#endif
#define CHECK_SIZEOF(TYPE, EXPECTED) \
if (EXPECTED != sizeof(TYPE)) { \
- PyErr_Format(TestError, \
+ PyErr_Format(get_testerror(self), \
"sizeof(%s) = %u instead of %u", \
#TYPE, sizeof(TYPE), EXPECTED); \
return (PyObject*)NULL; \
@@ -97,7 +114,7 @@ test_sizeof_c_types(PyObject *self, PyObject *Py_UNUSED(ignored))
#define IS_SIGNED(TYPE) (((TYPE)-1) < (TYPE)0)
#define CHECK_SIGNNESS(TYPE, SIGNED) \
if (IS_SIGNED(TYPE) != SIGNED) { \
- PyErr_Format(TestError, \
+ PyErr_Format(get_testerror(self), \
"%s signness is, instead of %i", \
#TYPE, IS_SIGNED(TYPE), SIGNED); \
return (PyObject*)NULL; \
@@ -170,7 +187,7 @@ test_list_api(PyObject *self, PyObject *Py_UNUSED(ignored))
for (i = 0; i < NLIST; ++i) {
PyObject* anint = PyList_GET_ITEM(list, i);
if (PyLong_AS_LONG(anint) != NLIST-1-i) {
- PyErr_SetString(TestError,
+ PyErr_SetString(get_testerror(self),
"test_list_api: reverse screwed up");
Py_DECREF(list);
return (PyObject*)NULL;
@@ -183,7 +200,7 @@ test_list_api(PyObject *self, PyObject *Py_UNUSED(ignored))
}
static int
-test_dict_inner(int count)
+test_dict_inner(PyObject *self, int count)
{
Py_ssize_t pos = 0, iterations = 0;
int i;
@@ -231,7 +248,7 @@ test_dict_inner(int count)
if (iterations != count) {
PyErr_SetString(
- TestError,
+ get_testerror(self),
"test_dict_iteration: dict iteration went wrong ");
return -1;
} else {
@@ -250,7 +267,7 @@ test_dict_iteration(PyObject* self, PyObject *Py_UNUSED(ignored))
int i;
for (i = 0; i < 200; i++) {
- if (test_dict_inner(i) < 0) {
+ if (test_dict_inner(self, i) < 0) {
return NULL;
}
}
@@ -334,14 +351,14 @@ test_lazy_hash_inheritance(PyObject* self, PyObject *Py_UNUSED(ignored))
if (obj == NULL) {
PyErr_Clear();
PyErr_SetString(
- TestError,
+ get_testerror(self),
"test_lazy_hash_inheritance: failed to create object");
return NULL;
}
if (type->tp_dict != NULL) {
PyErr_SetString(
- TestError,
+ get_testerror(self),
"test_lazy_hash_inheritance: type initialised too soon");
Py_DECREF(obj);
return NULL;
@@ -351,7 +368,7 @@ test_lazy_hash_inheritance(PyObject* self, PyObject *Py_UNUSED(ignored))
if ((hash == -1) && PyErr_Occurred()) {
PyErr_Clear();
PyErr_SetString(
- TestError,
+ get_testerror(self),
"test_lazy_hash_inheritance: could not hash object");
Py_DECREF(obj);
return NULL;
@@ -359,7 +376,7 @@ test_lazy_hash_inheritance(PyObject* self, PyObject *Py_UNUSED(ignored))
if (type->tp_dict == NULL) {
PyErr_SetString(
- TestError,
+ get_testerror(self),
"test_lazy_hash_inheritance: type not initialised by hash()");
Py_DECREF(obj);
return NULL;
@@ -367,7 +384,7 @@ test_lazy_hash_inheritance(PyObject* self, PyObject *Py_UNUSED(ignored))
if (type->tp_hash != PyType_Type.tp_hash) {
PyErr_SetString(
- TestError,
+ get_testerror(self),
"test_lazy_hash_inheritance: unexpected hash function");
Py_DECREF(obj);
return NULL;
@@ -427,7 +444,7 @@ py_buildvalue_ints(PyObject *self, PyObject *args)
}
static int
-test_buildvalue_N_error(const char *fmt)
+test_buildvalue_N_error(PyObject *self, const char *fmt)
{
PyObject *arg, *res;
@@ -443,7 +460,7 @@ test_buildvalue_N_error(const char *fmt)
}
Py_DECREF(res);
if (Py_REFCNT(arg) != 1) {
- PyErr_Format(TestError, "test_buildvalue_N: "
+ PyErr_Format(get_testerror(self), "test_buildvalue_N: "
"arg was not decrefed in successful "
"Py_BuildValue(\"%s\")", fmt);
return -1;
@@ -452,13 +469,13 @@ test_buildvalue_N_error(const char *fmt)
Py_INCREF(arg);
res = Py_BuildValue(fmt, raise_error, NULL, arg);
if (res != NULL || !PyErr_Occurred()) {
- PyErr_Format(TestError, "test_buildvalue_N: "
+ PyErr_Format(get_testerror(self), "test_buildvalue_N: "
"Py_BuildValue(\"%s\") didn't complain", fmt);
return -1;
}
PyErr_Clear();
if (Py_REFCNT(arg) != 1) {
- PyErr_Format(TestError, "test_buildvalue_N: "
+ PyErr_Format(get_testerror(self), "test_buildvalue_N: "
"arg was not decrefed in failed "
"Py_BuildValue(\"%s\")", fmt);
return -1;
@@ -482,25 +499,25 @@ test_buildvalue_N(PyObject *self, PyObject *Py_UNUSED(ignored))
return NULL;
}
if (res != arg) {
- return raiseTestError("test_buildvalue_N",
+ return raiseTestError(self, "test_buildvalue_N",
"Py_BuildValue(\"N\") returned wrong result");
}
if (Py_REFCNT(arg) != 2) {
- return raiseTestError("test_buildvalue_N",
+ return raiseTestError(self, "test_buildvalue_N",
"arg was not decrefed in Py_BuildValue(\"N\")");
}
Py_DECREF(res);
Py_DECREF(arg);
- if (test_buildvalue_N_error("O&N") < 0)
+ if (test_buildvalue_N_error(self, "O&N") < 0)
return NULL;
- if (test_buildvalue_N_error("(O&N)") < 0)
+ if (test_buildvalue_N_error(self, "(O&N)") < 0)
return NULL;
- if (test_buildvalue_N_error("[O&N]") < 0)
+ if (test_buildvalue_N_error(self, "[O&N]") < 0)
return NULL;
- if (test_buildvalue_N_error("{O&N}") < 0)
+ if (test_buildvalue_N_error(self, "{O&N}") < 0)
return NULL;
- if (test_buildvalue_N_error("{()O&(())N}") < 0)
+ if (test_buildvalue_N_error(self, "{()O&(())N}") < 0)
return NULL;
Py_RETURN_NONE;
@@ -910,7 +927,7 @@ test_string_to_double(PyObject *self, PyObject *Py_UNUSED(ignored)) {
Py_RETURN_NONE;
fail:
- return raiseTestError("test_string_to_double", msg);
+ return raiseTestError(self, "test_string_to_double", msg);
#undef CHECK_STRING
#undef CHECK_INVALID
}
@@ -1061,7 +1078,7 @@ test_capsule(PyObject *self, PyObject *Py_UNUSED(ignored))
exit:
if (error) {
- return raiseTestError("test_capsule", error);
+ return raiseTestError(self, "test_capsule", error);
}
Py_RETURN_NONE;
#undef FAIL
@@ -1272,7 +1289,7 @@ test_from_contiguous(PyObject* self, PyObject *Py_UNUSED(ignored))
ptr = view.buf;
for (i = 0; i < 5; i++) {
if (ptr[2*i] != i) {
- PyErr_SetString(TestError,
+ PyErr_SetString(get_testerror(self),
"test_from_contiguous: incorrect result");
return NULL;
}
@@ -1285,7 +1302,7 @@ test_from_contiguous(PyObject* self, PyObject *Py_UNUSED(ignored))
ptr = view.buf;
for (i = 0; i < 5; i++) {
if (*(ptr-2*i) != i) {
- PyErr_SetString(TestError,
+ PyErr_SetString(get_testerror(self),
"test_from_contiguous: incorrect result");
return NULL;
}
@@ -1338,7 +1355,7 @@ test_pep3118_obsolete_write_locks(PyObject* self, PyObject *Py_UNUSED(ignored))
Py_RETURN_NONE;
error:
- PyErr_SetString(TestError,
+ PyErr_SetString(get_testerror(self),
"test_pep3118_obsolete_write_locks: failure");
return NULL;
}
@@ -1959,7 +1976,7 @@ test_pythread_tss_key_state(PyObject *self, PyObject *args)
{
Py_tss_t tss_key = Py_tss_NEEDS_INIT;
if (PyThread_tss_is_created(&tss_key)) {
- return raiseTestError("test_pythread_tss_key_state",
+ return raiseTestError(self, "test_pythread_tss_key_state",
"TSS key not in an uninitialized state at "
"creation time");
}
@@ -1968,19 +1985,19 @@ test_pythread_tss_key_state(PyObject *self, PyObject *args)
return NULL;
}
if (!PyThread_tss_is_created(&tss_key)) {
- return raiseTestError("test_pythread_tss_key_state",
+ return raiseTestError(self, "test_pythread_tss_key_state",
"PyThread_tss_create succeeded, "
"but with TSS key in an uninitialized state");
}
if (PyThread_tss_create(&tss_key) != 0) {
- return raiseTestError("test_pythread_tss_key_state",
+ return raiseTestError(self, "test_pythread_tss_key_state",
"PyThread_tss_create unsuccessful with "
"an already initialized key");
}
#define CHECK_TSS_API(expr) \
(void)(expr); \
if (!PyThread_tss_is_created(&tss_key)) { \
- return raiseTestError("test_pythread_tss_key_state", \
+ return raiseTestError(self, "test_pythread_tss_key_state", \
"TSS key initialization state was not " \
"preserved after calling " #expr); }
CHECK_TSS_API(PyThread_tss_set(&tss_key, NULL));
@@ -1988,7 +2005,7 @@ test_pythread_tss_key_state(PyObject *self, PyObject *args)
#undef CHECK_TSS_API
PyThread_tss_delete(&tss_key);
if (PyThread_tss_is_created(&tss_key)) {
- return raiseTestError("test_pythread_tss_key_state",
+ return raiseTestError(self, "test_pythread_tss_key_state",
"PyThread_tss_delete called, but did not "
"set the key state to uninitialized");
}
@@ -1999,7 +2016,7 @@ test_pythread_tss_key_state(PyObject *self, PyObject *args)
return NULL;
}
if (PyThread_tss_is_created(ptr_key)) {
- return raiseTestError("test_pythread_tss_key_state",
+ return raiseTestError(self, "test_pythread_tss_key_state",
"TSS key not in an uninitialized state at "
"allocation time");
}
@@ -3831,14 +3848,9 @@ static PyTypeObject ContainerNoGC_type = {
static struct PyModuleDef _testcapimodule = {
PyModuleDef_HEAD_INIT,
- "_testcapi",
- NULL,
- -1,
- TestMethods,
- NULL,
- NULL,
- NULL,
- NULL
+ .m_name = "_testcapi",
+ .m_size = sizeof(testcapistate_t),
+ .m_methods = TestMethods,
};
/* Per PEP 489, this module will not be converted to multi-phase initialization
@@ -3933,9 +3945,10 @@ PyInit__testcapi(void)
PyModule_AddIntConstant(m, "the_number_three", 3);
PyModule_AddIntMacro(m, Py_C_RECURSION_LIMIT);
- TestError = PyErr_NewException("_testcapi.error", NULL, NULL);
- Py_INCREF(TestError);
- PyModule_AddObject(m, "error", TestError);
+ testcapistate_t *state = get_testcapi_state(m);
+ state->error = PyErr_NewException("_testcapi.error", NULL, NULL);
+ Py_INCREF(state->error);
+ PyModule_AddObject(m, "error", state->error);
if (PyType_Ready(&ContainerNoGC_type) < 0) {
return NULL;