From 324e9ee97e193eb3c4144f9cd5a0560b2c380893 Mon Sep 17 00:00:00 2001 From: Christian Heimes Date: Thu, 19 Nov 2020 12:07:07 +0100 Subject: [PATCH 1/2] bpo-1635741: Prepare _struct for multiphase initialization Signed-off-by: Christian Heimes --- ...2020-11-19-12-06-43.bpo-1635741.KEfZpn.rst | 1 + Modules/_struct.c | 458 ++++++++++-------- 2 files changed, 245 insertions(+), 214 deletions(-) create mode 100644 Misc/NEWS.d/next/C API/2020-11-19-12-06-43.bpo-1635741.KEfZpn.rst diff --git a/Misc/NEWS.d/next/C API/2020-11-19-12-06-43.bpo-1635741.KEfZpn.rst b/Misc/NEWS.d/next/C API/2020-11-19-12-06-43.bpo-1635741.KEfZpn.rst new file mode 100644 index 00000000000000..ef6d7b8ba7cdd6 --- /dev/null +++ b/Misc/NEWS.d/next/C API/2020-11-19-12-06-43.bpo-1635741.KEfZpn.rst @@ -0,0 +1 @@ +Prepare _struct extension module for multiphase initialization diff --git a/Modules/_struct.c b/Modules/_struct.c index 81cdbb9b817d31..20e0386b7aa4c6 100644 --- a/Modules/_struct.c +++ b/Modules/_struct.c @@ -31,15 +31,19 @@ get_struct_state(PyObject *module) static struct PyModuleDef _structmodule; #define _structmodulestate_global get_struct_state(PyState_FindModule(&_structmodule)) +#define get_struct_state_structinst(self) \ + (get_struct_state(_PyType_GetModuleByDef(Py_TYPE(self), &_structmodule))) +#define get_struct_state_iterinst(self) \ + (get_struct_state(PyType_GetModule(Py_TYPE(self)))) /* The translation function for each format character is table driven */ typedef struct _formatdef { char format; Py_ssize_t size; Py_ssize_t alignment; - PyObject* (*unpack)(const char *, + PyObject* (*unpack)(_structmodulestate *, const char *, const struct _formatdef *); - int (*pack)(char *, PyObject *, + int (*pack)(_structmodulestate *, char *, PyObject *, const struct _formatdef *); } formatdef; @@ -61,10 +65,7 @@ typedef struct { PyObject *weakreflist; /* List of weak references */ } PyStructObject; - -#define PyStruct_Check(op) PyObject_TypeCheck(op, (PyTypeObject *)_structmodulestate_global->PyStructType) -#define PyStruct_CheckExact(op) Py_IS_TYPE(op, (PyTypeObject *)_structmodulestate_global->PyStructType) - +#define PyStruct_Check(op, state) PyObject_TypeCheck(op, (PyTypeObject *)(state)->PyStructType) /* Define various structs to figure out the alignments of types */ @@ -115,7 +116,7 @@ static int cache_struct_converter(PyObject *, PyStructObject **); PyLongObject if possible, otherwise fails. Caller should decref. */ static PyObject * -get_pylong(PyObject *v) +get_pylong(_structmodulestate *state, PyObject *v) { assert(v != NULL); if (!PyLong_Check(v)) { @@ -126,7 +127,7 @@ get_pylong(PyObject *v) return NULL; } else { - PyErr_SetString(_structmodulestate_global->StructError, + PyErr_SetString(state->StructError, "required argument is not an integer"); return NULL; } @@ -142,11 +143,11 @@ get_pylong(PyObject *v) one */ static int -get_long(PyObject *v, long *p) +get_long(_structmodulestate *state, PyObject *v, long *p) { long x; - v = get_pylong(v); + v = get_pylong(state, v); if (v == NULL) return -1; assert(PyLong_Check(v)); @@ -154,7 +155,7 @@ get_long(PyObject *v, long *p) Py_DECREF(v); if (x == (long)-1 && PyErr_Occurred()) { if (PyErr_ExceptionMatches(PyExc_OverflowError)) - PyErr_SetString(_structmodulestate_global->StructError, + PyErr_SetString(state->StructError, "argument out of range"); return -1; } @@ -166,11 +167,11 @@ get_long(PyObject *v, long *p) /* Same, but handling unsigned long */ static int -get_ulong(PyObject *v, unsigned long *p) +get_ulong(_structmodulestate *state, PyObject *v, unsigned long *p) { unsigned long x; - v = get_pylong(v); + v = get_pylong(state, v); if (v == NULL) return -1; assert(PyLong_Check(v)); @@ -178,7 +179,7 @@ get_ulong(PyObject *v, unsigned long *p) Py_DECREF(v); if (x == (unsigned long)-1 && PyErr_Occurred()) { if (PyErr_ExceptionMatches(PyExc_OverflowError)) - PyErr_SetString(_structmodulestate_global->StructError, + PyErr_SetString(state->StructError, "argument out of range"); return -1; } @@ -189,11 +190,11 @@ get_ulong(PyObject *v, unsigned long *p) /* Same, but handling native long long. */ static int -get_longlong(PyObject *v, long long *p) +get_longlong(_structmodulestate *state, PyObject *v, long long *p) { long long x; - v = get_pylong(v); + v = get_pylong(state, v); if (v == NULL) return -1; assert(PyLong_Check(v)); @@ -201,7 +202,7 @@ get_longlong(PyObject *v, long long *p) Py_DECREF(v); if (x == (long long)-1 && PyErr_Occurred()) { if (PyErr_ExceptionMatches(PyExc_OverflowError)) - PyErr_SetString(_structmodulestate_global->StructError, + PyErr_SetString(state->StructError, "argument out of range"); return -1; } @@ -212,11 +213,11 @@ get_longlong(PyObject *v, long long *p) /* Same, but handling native unsigned long long. */ static int -get_ulonglong(PyObject *v, unsigned long long *p) +get_ulonglong(_structmodulestate *state, PyObject *v, unsigned long long *p) { unsigned long long x; - v = get_pylong(v); + v = get_pylong(state, v); if (v == NULL) return -1; assert(PyLong_Check(v)); @@ -224,7 +225,7 @@ get_ulonglong(PyObject *v, unsigned long long *p) Py_DECREF(v); if (x == (unsigned long long)-1 && PyErr_Occurred()) { if (PyErr_ExceptionMatches(PyExc_OverflowError)) - PyErr_SetString(_structmodulestate_global->StructError, + PyErr_SetString(state->StructError, "argument out of range"); return -1; } @@ -235,11 +236,11 @@ get_ulonglong(PyObject *v, unsigned long long *p) /* Same, but handling Py_ssize_t */ static int -get_ssize_t(PyObject *v, Py_ssize_t *p) +get_ssize_t(_structmodulestate *state, PyObject *v, Py_ssize_t *p) { Py_ssize_t x; - v = get_pylong(v); + v = get_pylong(state, v); if (v == NULL) return -1; assert(PyLong_Check(v)); @@ -247,7 +248,7 @@ get_ssize_t(PyObject *v, Py_ssize_t *p) Py_DECREF(v); if (x == (Py_ssize_t)-1 && PyErr_Occurred()) { if (PyErr_ExceptionMatches(PyExc_OverflowError)) - PyErr_SetString(_structmodulestate_global->StructError, + PyErr_SetString(state->StructError, "argument out of range"); return -1; } @@ -258,11 +259,11 @@ get_ssize_t(PyObject *v, Py_ssize_t *p) /* Same, but handling size_t */ static int -get_size_t(PyObject *v, size_t *p) +get_size_t(_structmodulestate *state, PyObject *v, size_t *p) { size_t x; - v = get_pylong(v); + v = get_pylong(state, v); if (v == NULL) return -1; assert(PyLong_Check(v)); @@ -270,7 +271,7 @@ get_size_t(PyObject *v, size_t *p) Py_DECREF(v); if (x == (size_t)-1 && PyErr_Occurred()) { if (PyErr_ExceptionMatches(PyExc_OverflowError)) - PyErr_SetString(_structmodulestate_global->StructError, + PyErr_SetString(state->StructError, "argument out of range"); return -1; } @@ -279,7 +280,7 @@ get_size_t(PyObject *v, size_t *p) } -#define RANGE_ERROR(x, f, flag, mask) return _range_error(f, flag) +#define RANGE_ERROR(state, x, f, flag, mask) return _range_error(state, f, flag) /* Floating point helpers */ @@ -298,13 +299,14 @@ unpack_halffloat(const char *p, /* start of 2-byte string */ } static int -pack_halffloat(char *p, /* start of 2-byte string */ +pack_halffloat(_structmodulestate *state, + char *p, /* start of 2-byte string */ PyObject *v, /* value to pack */ int le) /* true for little-endian, false for big-endian */ { double x = PyFloat_AsDouble(v); if (x == -1.0 && PyErr_Occurred()) { - PyErr_SetString(_structmodulestate_global->StructError, + PyErr_SetString(state->StructError, "required argument is not a float"); return -1; } @@ -337,7 +339,7 @@ unpack_double(const char *p, /* start of 8-byte string */ /* Helper to format the range error exceptions */ static int -_range_error(const formatdef *f, int is_unsigned) +_range_error(_structmodulestate *state, const formatdef *f, int is_unsigned) { /* ulargest is the largest unsigned value with f->size bytes. * Note that the simpler: @@ -350,13 +352,13 @@ _range_error(const formatdef *f, int is_unsigned) const size_t ulargest = (size_t)-1 >> ((SIZEOF_SIZE_T - f->size)*8); assert(f->size >= 1 && f->size <= SIZEOF_SIZE_T); if (is_unsigned) - PyErr_Format(_structmodulestate_global->StructError, + PyErr_Format(state->StructError, "'%c' format requires 0 <= number <= %zu", f->format, ulargest); else { const Py_ssize_t largest = (Py_ssize_t)(ulargest >> 1); - PyErr_Format(_structmodulestate_global->StructError, + PyErr_Format(state->StructError, "'%c' format requires %zd <= number <= %zd", f->format, ~ largest, @@ -388,25 +390,25 @@ _range_error(const formatdef *f, int is_unsigned) does this). */ static PyObject * -nu_char(const char *p, const formatdef *f) +nu_char(_structmodulestate *state, const char *p, const formatdef *f) { return PyBytes_FromStringAndSize(p, 1); } static PyObject * -nu_byte(const char *p, const formatdef *f) +nu_byte(_structmodulestate *state, const char *p, const formatdef *f) { return PyLong_FromLong((long) *(signed char *)p); } static PyObject * -nu_ubyte(const char *p, const formatdef *f) +nu_ubyte(_structmodulestate *state, const char *p, const formatdef *f) { return PyLong_FromLong((long) *(unsigned char *)p); } static PyObject * -nu_short(const char *p, const formatdef *f) +nu_short(_structmodulestate *state, const char *p, const formatdef *f) { short x; memcpy((char *)&x, p, sizeof x); @@ -414,7 +416,7 @@ nu_short(const char *p, const formatdef *f) } static PyObject * -nu_ushort(const char *p, const formatdef *f) +nu_ushort(_structmodulestate *state, const char *p, const formatdef *f) { unsigned short x; memcpy((char *)&x, p, sizeof x); @@ -422,7 +424,7 @@ nu_ushort(const char *p, const formatdef *f) } static PyObject * -nu_int(const char *p, const formatdef *f) +nu_int(_structmodulestate *state, const char *p, const formatdef *f) { int x; memcpy((char *)&x, p, sizeof x); @@ -430,7 +432,7 @@ nu_int(const char *p, const formatdef *f) } static PyObject * -nu_uint(const char *p, const formatdef *f) +nu_uint(_structmodulestate *state, const char *p, const formatdef *f) { unsigned int x; memcpy((char *)&x, p, sizeof x); @@ -438,7 +440,7 @@ nu_uint(const char *p, const formatdef *f) } static PyObject * -nu_long(const char *p, const formatdef *f) +nu_long(_structmodulestate *state, const char *p, const formatdef *f) { long x; memcpy((char *)&x, p, sizeof x); @@ -446,7 +448,7 @@ nu_long(const char *p, const formatdef *f) } static PyObject * -nu_ulong(const char *p, const formatdef *f) +nu_ulong(_structmodulestate *state, const char *p, const formatdef *f) { unsigned long x; memcpy((char *)&x, p, sizeof x); @@ -454,7 +456,7 @@ nu_ulong(const char *p, const formatdef *f) } static PyObject * -nu_ssize_t(const char *p, const formatdef *f) +nu_ssize_t(_structmodulestate *state, const char *p, const formatdef *f) { Py_ssize_t x; memcpy((char *)&x, p, sizeof x); @@ -462,7 +464,7 @@ nu_ssize_t(const char *p, const formatdef *f) } static PyObject * -nu_size_t(const char *p, const formatdef *f) +nu_size_t(_structmodulestate *state, const char *p, const formatdef *f) { size_t x; memcpy((char *)&x, p, sizeof x); @@ -470,7 +472,7 @@ nu_size_t(const char *p, const formatdef *f) } static PyObject * -nu_longlong(const char *p, const formatdef *f) +nu_longlong(_structmodulestate *state, const char *p, const formatdef *f) { long long x; memcpy((char *)&x, p, sizeof x); @@ -478,7 +480,7 @@ nu_longlong(const char *p, const formatdef *f) } static PyObject * -nu_ulonglong(const char *p, const formatdef *f) +nu_ulonglong(_structmodulestate *state, const char *p, const formatdef *f) { unsigned long long x; memcpy((char *)&x, p, sizeof x); @@ -486,7 +488,7 @@ nu_ulonglong(const char *p, const formatdef *f) } static PyObject * -nu_bool(const char *p, const formatdef *f) +nu_bool(_structmodulestate *state, const char *p, const formatdef *f) { _Bool x; memcpy((char *)&x, p, sizeof x); @@ -495,7 +497,7 @@ nu_bool(const char *p, const formatdef *f) static PyObject * -nu_halffloat(const char *p, const formatdef *f) +nu_halffloat(_structmodulestate *state, const char *p, const formatdef *f) { #if PY_LITTLE_ENDIAN return unpack_halffloat(p, 1); @@ -505,7 +507,7 @@ nu_halffloat(const char *p, const formatdef *f) } static PyObject * -nu_float(const char *p, const formatdef *f) +nu_float(_structmodulestate *state, const char *p, const formatdef *f) { float x; memcpy((char *)&x, p, sizeof x); @@ -513,7 +515,7 @@ nu_float(const char *p, const formatdef *f) } static PyObject * -nu_double(const char *p, const formatdef *f) +nu_double(_structmodulestate *state, const char *p, const formatdef *f) { double x; memcpy((char *)&x, p, sizeof x); @@ -521,7 +523,7 @@ nu_double(const char *p, const formatdef *f) } static PyObject * -nu_void_p(const char *p, const formatdef *f) +nu_void_p(_structmodulestate *state, const char *p, const formatdef *f) { void *x; memcpy((char *)&x, p, sizeof x); @@ -529,13 +531,13 @@ nu_void_p(const char *p, const formatdef *f) } static int -np_byte(char *p, PyObject *v, const formatdef *f) +np_byte(_structmodulestate *state, char *p, PyObject *v, const formatdef *f) { long x; - if (get_long(v, &x) < 0) + if (get_long(state, v, &x) < 0) return -1; if (x < -128 || x > 127) { - PyErr_SetString(_structmodulestate_global->StructError, + PyErr_SetString(state->StructError, "byte format requires -128 <= number <= 127"); return -1; } @@ -544,13 +546,13 @@ np_byte(char *p, PyObject *v, const formatdef *f) } static int -np_ubyte(char *p, PyObject *v, const formatdef *f) +np_ubyte(_structmodulestate *state, char *p, PyObject *v, const formatdef *f) { long x; - if (get_long(v, &x) < 0) + if (get_long(state, v, &x) < 0) return -1; if (x < 0 || x > 255) { - PyErr_SetString(_structmodulestate_global->StructError, + PyErr_SetString(state->StructError, "ubyte format requires 0 <= number <= 255"); return -1; } @@ -559,10 +561,10 @@ np_ubyte(char *p, PyObject *v, const formatdef *f) } static int -np_char(char *p, PyObject *v, const formatdef *f) +np_char(_structmodulestate *state, char *p, PyObject *v, const formatdef *f) { if (!PyBytes_Check(v) || PyBytes_Size(v) != 1) { - PyErr_SetString(_structmodulestate_global->StructError, + PyErr_SetString(state->StructError, "char format requires a bytes object of length 1"); return -1; } @@ -571,14 +573,14 @@ np_char(char *p, PyObject *v, const formatdef *f) } static int -np_short(char *p, PyObject *v, const formatdef *f) +np_short(_structmodulestate *state, char *p, PyObject *v, const formatdef *f) { long x; short y; - if (get_long(v, &x) < 0) + if (get_long(state, v, &x) < 0) return -1; if (x < SHRT_MIN || x > SHRT_MAX) { - PyErr_SetString(_structmodulestate_global->StructError, + PyErr_SetString(state->StructError, "short format requires " Py_STRINGIFY(SHRT_MIN) " <= number <= " Py_STRINGIFY(SHRT_MAX)); return -1; @@ -589,14 +591,14 @@ np_short(char *p, PyObject *v, const formatdef *f) } static int -np_ushort(char *p, PyObject *v, const formatdef *f) +np_ushort(_structmodulestate *state, char *p, PyObject *v, const formatdef *f) { long x; unsigned short y; - if (get_long(v, &x) < 0) + if (get_long(state, v, &x) < 0) return -1; if (x < 0 || x > USHRT_MAX) { - PyErr_SetString(_structmodulestate_global->StructError, + PyErr_SetString(state->StructError, "ushort format requires 0 <= number <= " Py_STRINGIFY(USHRT_MAX)); return -1; @@ -607,15 +609,15 @@ np_ushort(char *p, PyObject *v, const formatdef *f) } static int -np_int(char *p, PyObject *v, const formatdef *f) +np_int(_structmodulestate *state, char *p, PyObject *v, const formatdef *f) { long x; int y; - if (get_long(v, &x) < 0) + if (get_long(state, v, &x) < 0) return -1; #if (SIZEOF_LONG > SIZEOF_INT) if ((x < ((long)INT_MIN)) || (x > ((long)INT_MAX))) - RANGE_ERROR(x, f, 0, -1); + RANGE_ERROR(state, x, f, 0, -1); #endif y = (int)x; memcpy(p, (char *)&y, sizeof y); @@ -623,76 +625,76 @@ np_int(char *p, PyObject *v, const formatdef *f) } static int -np_uint(char *p, PyObject *v, const formatdef *f) +np_uint(_structmodulestate *state, char *p, PyObject *v, const formatdef *f) { unsigned long x; unsigned int y; - if (get_ulong(v, &x) < 0) + if (get_ulong(state, v, &x) < 0) return -1; y = (unsigned int)x; #if (SIZEOF_LONG > SIZEOF_INT) if (x > ((unsigned long)UINT_MAX)) - RANGE_ERROR(y, f, 1, -1); + RANGE_ERROR(state, y, f, 1, -1); #endif memcpy(p, (char *)&y, sizeof y); return 0; } static int -np_long(char *p, PyObject *v, const formatdef *f) +np_long(_structmodulestate *state, char *p, PyObject *v, const formatdef *f) { long x; - if (get_long(v, &x) < 0) + if (get_long(state, v, &x) < 0) return -1; memcpy(p, (char *)&x, sizeof x); return 0; } static int -np_ulong(char *p, PyObject *v, const formatdef *f) +np_ulong(_structmodulestate *state, char *p, PyObject *v, const formatdef *f) { unsigned long x; - if (get_ulong(v, &x) < 0) + if (get_ulong(state, v, &x) < 0) return -1; memcpy(p, (char *)&x, sizeof x); return 0; } static int -np_ssize_t(char *p, PyObject *v, const formatdef *f) +np_ssize_t(_structmodulestate *state, char *p, PyObject *v, const formatdef *f) { Py_ssize_t x; - if (get_ssize_t(v, &x) < 0) + if (get_ssize_t(state, v, &x) < 0) return -1; memcpy(p, (char *)&x, sizeof x); return 0; } static int -np_size_t(char *p, PyObject *v, const formatdef *f) +np_size_t(_structmodulestate *state, char *p, PyObject *v, const formatdef *f) { size_t x; - if (get_size_t(v, &x) < 0) + if (get_size_t(state, v, &x) < 0) return -1; memcpy(p, (char *)&x, sizeof x); return 0; } static int -np_longlong(char *p, PyObject *v, const formatdef *f) +np_longlong(_structmodulestate *state, char *p, PyObject *v, const formatdef *f) { long long x; - if (get_longlong(v, &x) < 0) + if (get_longlong(state, v, &x) < 0) return -1; memcpy(p, (char *)&x, sizeof x); return 0; } static int -np_ulonglong(char *p, PyObject *v, const formatdef *f) +np_ulonglong(_structmodulestate *state, char *p, PyObject *v, const formatdef *f) { unsigned long long x; - if (get_ulonglong(v, &x) < 0) + if (get_ulonglong(state, v, &x) < 0) return -1; memcpy(p, (char *)&x, sizeof x); return 0; @@ -700,7 +702,7 @@ np_ulonglong(char *p, PyObject *v, const formatdef *f) static int -np_bool(char *p, PyObject *v, const formatdef *f) +np_bool(_structmodulestate *state, char *p, PyObject *v, const formatdef *f) { int y; _Bool x; @@ -713,21 +715,21 @@ np_bool(char *p, PyObject *v, const formatdef *f) } static int -np_halffloat(char *p, PyObject *v, const formatdef *f) +np_halffloat(_structmodulestate *state, char *p, PyObject *v, const formatdef *f) { #if PY_LITTLE_ENDIAN - return pack_halffloat(p, v, 1); + return pack_halffloat(state, p, v, 1); #else - return pack_halffloat(p, v, 0); + return pack_halffloat(statem p, v, 0); #endif } static int -np_float(char *p, PyObject *v, const formatdef *f) +np_float(_structmodulestate *state, char *p, PyObject *v, const formatdef *f) { float x = (float)PyFloat_AsDouble(v); if (x == -1 && PyErr_Occurred()) { - PyErr_SetString(_structmodulestate_global->StructError, + PyErr_SetString(state->StructError, "required argument is not a float"); return -1; } @@ -736,11 +738,11 @@ np_float(char *p, PyObject *v, const formatdef *f) } static int -np_double(char *p, PyObject *v, const formatdef *f) +np_double(_structmodulestate *state, char *p, PyObject *v, const formatdef *f) { double x = PyFloat_AsDouble(v); if (x == -1 && PyErr_Occurred()) { - PyErr_SetString(_structmodulestate_global->StructError, + PyErr_SetString(state->StructError, "required argument is not a float"); return -1; } @@ -749,11 +751,11 @@ np_double(char *p, PyObject *v, const formatdef *f) } static int -np_void_p(char *p, PyObject *v, const formatdef *f) +np_void_p(_structmodulestate *state, char *p, PyObject *v, const formatdef *f) { void *x; - v = get_pylong(v); + v = get_pylong(state, v); if (v == NULL) return -1; assert(PyLong_Check(v)); @@ -793,7 +795,7 @@ static const formatdef native_table[] = { /* Big-endian routines. *****************************************************/ static PyObject * -bu_int(const char *p, const formatdef *f) +bu_int(_structmodulestate *state, const char *p, const formatdef *f) { long x = 0; Py_ssize_t i = f->size; @@ -808,7 +810,7 @@ bu_int(const char *p, const formatdef *f) } static PyObject * -bu_uint(const char *p, const formatdef *f) +bu_uint(_structmodulestate *state, const char *p, const formatdef *f) { unsigned long x = 0; Py_ssize_t i = f->size; @@ -820,7 +822,7 @@ bu_uint(const char *p, const formatdef *f) } static PyObject * -bu_longlong(const char *p, const formatdef *f) +bu_longlong(_structmodulestate *state, const char *p, const formatdef *f) { long long x = 0; Py_ssize_t i = f->size; @@ -835,7 +837,7 @@ bu_longlong(const char *p, const formatdef *f) } static PyObject * -bu_ulonglong(const char *p, const formatdef *f) +bu_ulonglong(_structmodulestate *state, const char *p, const formatdef *f) { unsigned long long x = 0; Py_ssize_t i = f->size; @@ -847,44 +849,44 @@ bu_ulonglong(const char *p, const formatdef *f) } static PyObject * -bu_halffloat(const char *p, const formatdef *f) +bu_halffloat(_structmodulestate *state, const char *p, const formatdef *f) { return unpack_halffloat(p, 0); } static PyObject * -bu_float(const char *p, const formatdef *f) +bu_float(_structmodulestate *state, const char *p, const formatdef *f) { return unpack_float(p, 0); } static PyObject * -bu_double(const char *p, const formatdef *f) +bu_double(_structmodulestate *state, const char *p, const formatdef *f) { return unpack_double(p, 0); } static PyObject * -bu_bool(const char *p, const formatdef *f) +bu_bool(_structmodulestate *state, const char *p, const formatdef *f) { return PyBool_FromLong(*p != 0); } static int -bp_int(char *p, PyObject *v, const formatdef *f) +bp_int(_structmodulestate *state, char *p, PyObject *v, const formatdef *f) { long x; Py_ssize_t i; unsigned char *q = (unsigned char *)p; - if (get_long(v, &x) < 0) + if (get_long(state, v, &x) < 0) return -1; i = f->size; if (i != SIZEOF_LONG) { if ((i == 2) && (x < -32768 || x > 32767)) - RANGE_ERROR(x, f, 0, 0xffffL); + RANGE_ERROR(state, x, f, 0, 0xffffL); #if (SIZEOF_LONG != 4) else if ((i == 4) && (x < -2147483648L || x > 2147483647L)) - RANGE_ERROR(x, f, 0, 0xffffffffL); + RANGE_ERROR(state, x, f, 0, 0xffffffffL); #endif } do { @@ -895,19 +897,19 @@ bp_int(char *p, PyObject *v, const formatdef *f) } static int -bp_uint(char *p, PyObject *v, const formatdef *f) +bp_uint(_structmodulestate *state, char *p, PyObject *v, const formatdef *f) { unsigned long x; Py_ssize_t i; unsigned char *q = (unsigned char *)p; - if (get_ulong(v, &x) < 0) + if (get_ulong(state, v, &x) < 0) return -1; i = f->size; if (i != SIZEOF_LONG) { unsigned long maxint = 1; maxint <<= (unsigned long)(i * 8); if (x >= maxint) - RANGE_ERROR(x, f, 1, maxint - 1); + RANGE_ERROR(state, x, f, 1, maxint - 1); } do { q[--i] = (unsigned char)(x & 0xffUL); @@ -917,10 +919,10 @@ bp_uint(char *p, PyObject *v, const formatdef *f) } static int -bp_longlong(char *p, PyObject *v, const formatdef *f) +bp_longlong(_structmodulestate *state, char *p, PyObject *v, const formatdef *f) { int res; - v = get_pylong(v); + v = get_pylong(state, v); if (v == NULL) return -1; res = _PyLong_AsByteArray((PyLongObject *)v, @@ -933,10 +935,10 @@ bp_longlong(char *p, PyObject *v, const formatdef *f) } static int -bp_ulonglong(char *p, PyObject *v, const formatdef *f) +bp_ulonglong(_structmodulestate *state, char *p, PyObject *v, const formatdef *f) { int res; - v = get_pylong(v); + v = get_pylong(state, v); if (v == NULL) return -1; res = _PyLong_AsByteArray((PyLongObject *)v, @@ -949,17 +951,17 @@ bp_ulonglong(char *p, PyObject *v, const formatdef *f) } static int -bp_halffloat(char *p, PyObject *v, const formatdef *f) +bp_halffloat(_structmodulestate *state, char *p, PyObject *v, const formatdef *f) { - return pack_halffloat(p, v, 0); + return pack_halffloat(state, p, v, 0); } static int -bp_float(char *p, PyObject *v, const formatdef *f) +bp_float(_structmodulestate *state, char *p, PyObject *v, const formatdef *f) { double x = PyFloat_AsDouble(v); if (x == -1 && PyErr_Occurred()) { - PyErr_SetString(_structmodulestate_global->StructError, + PyErr_SetString(state->StructError, "required argument is not a float"); return -1; } @@ -967,11 +969,11 @@ bp_float(char *p, PyObject *v, const formatdef *f) } static int -bp_double(char *p, PyObject *v, const formatdef *f) +bp_double(_structmodulestate *state, char *p, PyObject *v, const formatdef *f) { double x = PyFloat_AsDouble(v); if (x == -1 && PyErr_Occurred()) { - PyErr_SetString(_structmodulestate_global->StructError, + PyErr_SetString(state->StructError, "required argument is not a float"); return -1; } @@ -979,7 +981,7 @@ bp_double(char *p, PyObject *v, const formatdef *f) } static int -bp_bool(char *p, PyObject *v, const formatdef *f) +bp_bool(_structmodulestate *state, char *p, PyObject *v, const formatdef *f) { int y; y = PyObject_IsTrue(v); @@ -1014,7 +1016,7 @@ static formatdef bigendian_table[] = { /* Little-endian routines. *****************************************************/ static PyObject * -lu_int(const char *p, const formatdef *f) +lu_int(_structmodulestate *state, const char *p, const formatdef *f) { long x = 0; Py_ssize_t i = f->size; @@ -1029,7 +1031,7 @@ lu_int(const char *p, const formatdef *f) } static PyObject * -lu_uint(const char *p, const formatdef *f) +lu_uint(_structmodulestate *state, const char *p, const formatdef *f) { unsigned long x = 0; Py_ssize_t i = f->size; @@ -1041,7 +1043,7 @@ lu_uint(const char *p, const formatdef *f) } static PyObject * -lu_longlong(const char *p, const formatdef *f) +lu_longlong(_structmodulestate *state, const char *p, const formatdef *f) { long long x = 0; Py_ssize_t i = f->size; @@ -1056,7 +1058,7 @@ lu_longlong(const char *p, const formatdef *f) } static PyObject * -lu_ulonglong(const char *p, const formatdef *f) +lu_ulonglong(_structmodulestate *state, const char *p, const formatdef *f) { unsigned long long x = 0; Py_ssize_t i = f->size; @@ -1068,38 +1070,38 @@ lu_ulonglong(const char *p, const formatdef *f) } static PyObject * -lu_halffloat(const char *p, const formatdef *f) +lu_halffloat(_structmodulestate *state, const char *p, const formatdef *f) { return unpack_halffloat(p, 1); } static PyObject * -lu_float(const char *p, const formatdef *f) +lu_float(_structmodulestate *state, const char *p, const formatdef *f) { return unpack_float(p, 1); } static PyObject * -lu_double(const char *p, const formatdef *f) +lu_double(_structmodulestate *state, const char *p, const formatdef *f) { return unpack_double(p, 1); } static int -lp_int(char *p, PyObject *v, const formatdef *f) +lp_int(_structmodulestate *state, char *p, PyObject *v, const formatdef *f) { long x; Py_ssize_t i; unsigned char *q = (unsigned char *)p; - if (get_long(v, &x) < 0) + if (get_long(state, v, &x) < 0) return -1; i = f->size; if (i != SIZEOF_LONG) { if ((i == 2) && (x < -32768 || x > 32767)) - RANGE_ERROR(x, f, 0, 0xffffL); + RANGE_ERROR(state, x, f, 0, 0xffffL); #if (SIZEOF_LONG != 4) else if ((i == 4) && (x < -2147483648L || x > 2147483647L)) - RANGE_ERROR(x, f, 0, 0xffffffffL); + RANGE_ERROR(state, x, f, 0, 0xffffffffL); #endif } do { @@ -1110,19 +1112,19 @@ lp_int(char *p, PyObject *v, const formatdef *f) } static int -lp_uint(char *p, PyObject *v, const formatdef *f) +lp_uint(_structmodulestate *state, char *p, PyObject *v, const formatdef *f) { unsigned long x; Py_ssize_t i; unsigned char *q = (unsigned char *)p; - if (get_ulong(v, &x) < 0) + if (get_ulong(state, v, &x) < 0) return -1; i = f->size; if (i != SIZEOF_LONG) { unsigned long maxint = 1; maxint <<= (unsigned long)(i * 8); if (x >= maxint) - RANGE_ERROR(x, f, 1, maxint - 1); + RANGE_ERROR(state, x, f, 1, maxint - 1); } do { *q++ = (unsigned char)(x & 0xffUL); @@ -1132,10 +1134,10 @@ lp_uint(char *p, PyObject *v, const formatdef *f) } static int -lp_longlong(char *p, PyObject *v, const formatdef *f) +lp_longlong(_structmodulestate *state, char *p, PyObject *v, const formatdef *f) { int res; - v = get_pylong(v); + v = get_pylong(state, v); if (v == NULL) return -1; res = _PyLong_AsByteArray((PyLongObject*)v, @@ -1148,10 +1150,10 @@ lp_longlong(char *p, PyObject *v, const formatdef *f) } static int -lp_ulonglong(char *p, PyObject *v, const formatdef *f) +lp_ulonglong(_structmodulestate *state, char *p, PyObject *v, const formatdef *f) { int res; - v = get_pylong(v); + v = get_pylong(state, v); if (v == NULL) return -1; res = _PyLong_AsByteArray((PyLongObject*)v, @@ -1164,17 +1166,17 @@ lp_ulonglong(char *p, PyObject *v, const formatdef *f) } static int -lp_halffloat(char *p, PyObject *v, const formatdef *f) +lp_halffloat(_structmodulestate *state, char *p, PyObject *v, const formatdef *f) { - return pack_halffloat(p, v, 1); + return pack_halffloat(state, p, v, 1); } static int -lp_float(char *p, PyObject *v, const formatdef *f) +lp_float(_structmodulestate *state, char *p, PyObject *v, const formatdef *f) { double x = PyFloat_AsDouble(v); if (x == -1 && PyErr_Occurred()) { - PyErr_SetString(_structmodulestate_global->StructError, + PyErr_SetString(state->StructError, "required argument is not a float"); return -1; } @@ -1182,11 +1184,11 @@ lp_float(char *p, PyObject *v, const formatdef *f) } static int -lp_double(char *p, PyObject *v, const formatdef *f) +lp_double(_structmodulestate *state, char *p, PyObject *v, const formatdef *f) { double x = PyFloat_AsDouble(v); if (x == -1 && PyErr_Occurred()) { - PyErr_SetString(_structmodulestate_global->StructError, + PyErr_SetString(state->StructError, "required argument is not a float"); return -1; } @@ -1246,14 +1248,14 @@ whichtable(const char **pfmt) /* Get the table entry for a format code */ static const formatdef * -getentry(int c, const formatdef *f) +getentry(_structmodulestate *state, int c, const formatdef *f) { for (; f->format != '\0'; f++) { if (f->format == c) { return f; } } - PyErr_SetString(_structmodulestate_global->StructError, "bad char in struct format"); + PyErr_SetString(state->StructError, "bad char in struct format"); return NULL; } @@ -1295,9 +1297,11 @@ prepare_s(PyStructObject *self) Py_ssize_t size, len, num, itemsize; size_t ncodes; + _structmodulestate *state = get_struct_state_structinst(self); + fmt = PyBytes_AS_STRING(self->s_format); if (strlen(fmt) != (size_t)PyBytes_GET_SIZE(self->s_format)) { - PyErr_SetString(_structmodulestate_global->StructError, + PyErr_SetString(state->StructError, "embedded null character"); return -1; } @@ -1323,7 +1327,7 @@ prepare_s(PyStructObject *self) num = num*10 + (c - '0'); } if (c == '\0') { - PyErr_SetString(_structmodulestate_global->StructError, + PyErr_SetString(state->StructError, "repeat count given without format specifier"); return -1; } @@ -1331,7 +1335,7 @@ prepare_s(PyStructObject *self) else num = 1; - e = getentry(c, f); + e = getentry(state, c, f); if (e == NULL) return -1; @@ -1384,7 +1388,7 @@ prepare_s(PyStructObject *self) else num = 1; - e = getentry(c, f); + e = getentry(state, c, f); size = align(size, c, e); if (c == 's' || c == 'p') { @@ -1413,7 +1417,7 @@ prepare_s(PyStructObject *self) return 0; overflow: - PyErr_SetString(_structmodulestate_global->StructError, + PyErr_SetString(state->StructError, "total struct size too long"); return -1; } @@ -1499,7 +1503,8 @@ s_dealloc(PyStructObject *s) } static PyObject * -s_unpack_internal(PyStructObject *soself, const char *startfrom) { +s_unpack_internal(PyStructObject *soself, const char *startfrom, + _structmodulestate *state) { formatcode *code; Py_ssize_t i = 0; PyObject *result = PyTuple_New(soself->s_len); @@ -1520,7 +1525,7 @@ s_unpack_internal(PyStructObject *soself, const char *startfrom) { n = code->size - 1; v = PyBytes_FromStringAndSize(res + 1, n); } else { - v = e->unpack(res, e); + v = e->unpack(state, res, e); } if (v == NULL) goto fail; @@ -1554,14 +1559,15 @@ static PyObject * Struct_unpack_impl(PyStructObject *self, Py_buffer *buffer) /*[clinic end generated code: output=873a24faf02e848a input=3113f8e7038b2f6c]*/ { + _structmodulestate *state = get_struct_state_structinst(self); assert(self->s_codes != NULL); if (buffer->len != self->s_size) { - PyErr_Format(_structmodulestate_global->StructError, + PyErr_Format(state->StructError, "unpack requires a buffer of %zd bytes", self->s_size); return NULL; } - return s_unpack_internal(self, buffer->buf); + return s_unpack_internal(self, buffer->buf, state); } /*[clinic input] @@ -1585,11 +1591,12 @@ Struct_unpack_from_impl(PyStructObject *self, Py_buffer *buffer, Py_ssize_t offset) /*[clinic end generated code: output=57fac875e0977316 input=cafd4851d473c894]*/ { + _structmodulestate *state = get_struct_state_structinst(self); assert(self->s_codes != NULL); if (offset < 0) { if (offset + self->s_size > 0) { - PyErr_Format(_structmodulestate_global->StructError, + PyErr_Format(state->StructError, "not enough data to unpack %zd bytes at offset %zd", self->s_size, offset); @@ -1597,7 +1604,7 @@ Struct_unpack_from_impl(PyStructObject *self, Py_buffer *buffer, } if (offset + buffer->len < 0) { - PyErr_Format(_structmodulestate_global->StructError, + PyErr_Format(state->StructError, "offset %zd out of range for %zd-byte buffer", offset, buffer->len); @@ -1607,7 +1614,7 @@ Struct_unpack_from_impl(PyStructObject *self, Py_buffer *buffer, } if ((buffer->len - offset) < self->s_size) { - PyErr_Format(_structmodulestate_global->StructError, + PyErr_Format(state->StructError, "unpack_from requires a buffer of at least %zu bytes for " "unpacking %zd bytes at offset %zd " "(actual buffer size is %zd)", @@ -1617,7 +1624,7 @@ Struct_unpack_from_impl(PyStructObject *self, Py_buffer *buffer, buffer->len); return NULL; } - return s_unpack_internal(self, (char*)buffer->buf + offset); + return s_unpack_internal(self, (char*)buffer->buf + offset, state); } @@ -1671,6 +1678,7 @@ static PyMethodDef unpackiter_methods[] = { static PyObject * unpackiter_iternext(unpackiterobject *self) { + _structmodulestate *state = get_struct_state_iterinst(self); PyObject *result; if (self->so == NULL) return NULL; @@ -1682,7 +1690,8 @@ unpackiter_iternext(unpackiterobject *self) } assert(self->index + self->so->s_size <= self->buf.len); result = s_unpack_internal(self->so, - (char*) self->buf.buf + self->index); + (char*) self->buf.buf + self->index, + state); self->index += self->so->s_size; return result; } @@ -1729,17 +1738,18 @@ static PyObject * Struct_iter_unpack(PyStructObject *self, PyObject *buffer) /*[clinic end generated code: output=172d83d0cd15dbab input=6d65b3f3107dbc99]*/ { + _structmodulestate *state = get_struct_state_structinst(self); unpackiterobject *iter; assert(self->s_codes != NULL); if (self->s_size == 0) { - PyErr_Format(_structmodulestate_global->StructError, + PyErr_Format(state->StructError, "cannot iteratively unpack with a struct of length 0"); return NULL; } - iter = (unpackiterobject *) PyType_GenericAlloc((PyTypeObject *)_structmodulestate_global->unpackiter_type, 0); + iter = (unpackiterobject *) PyType_GenericAlloc((PyTypeObject *)state->unpackiter_type, 0); if (iter == NULL) return NULL; @@ -1748,7 +1758,7 @@ Struct_iter_unpack(PyStructObject *self, PyObject *buffer) return NULL; } if (iter->buf.len % self->s_size != 0) { - PyErr_Format(_structmodulestate_global->StructError, + PyErr_Format(state->StructError, "iterative unpacking requires a buffer of " "a multiple of %zd bytes", self->s_size); @@ -1773,7 +1783,8 @@ Struct_iter_unpack(PyStructObject *self, PyObject *buffer) * */ static int -s_pack_internal(PyStructObject *soself, PyObject *const *args, int offset, char* buf) +s_pack_internal(PyStructObject *soself, PyObject *const *args, int offset, + char* buf, _structmodulestate *state) { formatcode *code; /* XXX(nnorwitz): why does i need to be a local? can we use @@ -1794,7 +1805,7 @@ s_pack_internal(PyStructObject *soself, PyObject *const *args, int offset, char* const void *p; isstring = PyBytes_Check(v); if (!isstring && !PyByteArray_Check(v)) { - PyErr_SetString(_structmodulestate_global->StructError, + PyErr_SetString(state->StructError, "argument for 's' must be a bytes object"); return -1; } @@ -1816,7 +1827,7 @@ s_pack_internal(PyStructObject *soself, PyObject *const *args, int offset, char* const void *p; isstring = PyBytes_Check(v); if (!isstring && !PyByteArray_Check(v)) { - PyErr_SetString(_structmodulestate_global->StructError, + PyErr_SetString(state->StructError, "argument for 'p' must be a bytes object"); return -1; } @@ -1836,9 +1847,9 @@ s_pack_internal(PyStructObject *soself, PyObject *const *args, int offset, char* n = 255; *res = Py_SAFE_DOWNCAST(n, Py_ssize_t, unsigned char); } else { - if (e->pack(res, v, e) < 0) { + if (e->pack(state, res, v, e) < 0) { if (PyLong_Check(v) && PyErr_ExceptionMatches(PyExc_OverflowError)) - PyErr_SetString(_structmodulestate_global->StructError, + PyErr_SetString(state->StructError, "int too large to convert"); return -1; } @@ -1864,14 +1875,15 @@ s_pack(PyObject *self, PyObject *const *args, Py_ssize_t nargs) { char *buf; PyStructObject *soself; + _structmodulestate *state = get_struct_state_structinst(self); /* Validate arguments. */ soself = (PyStructObject *)self; - assert(PyStruct_Check(self)); + assert(PyStruct_Check(self, state)); assert(soself->s_codes != NULL); if (nargs != soself->s_len) { - PyErr_Format(_structmodulestate_global->StructError, + PyErr_Format(state->StructError, "pack expected %zd items for packing (got %zd)", soself->s_len, nargs); return NULL; } @@ -1886,7 +1898,7 @@ s_pack(PyObject *self, PyObject *const *args, Py_ssize_t nargs) } /* Call the guts */ - if ( s_pack_internal(soself, args, 0, buf) != 0 ) { + if ( s_pack_internal(soself, args, 0, buf, state) != 0 ) { _PyBytesWriter_Dealloc(&writer); return NULL; } @@ -1908,23 +1920,24 @@ s_pack_into(PyObject *self, PyObject *const *args, Py_ssize_t nargs) PyStructObject *soself; Py_buffer buffer; Py_ssize_t offset; + _structmodulestate *state = get_struct_state_structinst(self); /* Validate arguments. +1 is for the first arg as buffer. */ soself = (PyStructObject *)self; - assert(PyStruct_Check(self)); + assert(PyStruct_Check(self, state)); assert(soself->s_codes != NULL); if (nargs != (soself->s_len + 2)) { if (nargs == 0) { - PyErr_Format(_structmodulestate_global->StructError, + PyErr_Format(state->StructError, "pack_into expected buffer argument"); } else if (nargs == 1) { - PyErr_Format(_structmodulestate_global->StructError, + PyErr_Format(state->StructError, "pack_into expected offset argument"); } else { - PyErr_Format(_structmodulestate_global->StructError, + PyErr_Format(state->StructError, "pack_into expected %zd items for packing (got %zd)", soself->s_len, (nargs - 2)); } @@ -1947,7 +1960,7 @@ s_pack_into(PyObject *self, PyObject *const *args, Py_ssize_t nargs) if (offset < 0) { /* Check that negative offset is low enough to fit data */ if (offset + soself->s_size > 0) { - PyErr_Format(_structmodulestate_global->StructError, + PyErr_Format(state->StructError, "no space to pack %zd bytes at offset %zd", soself->s_size, offset); @@ -1957,7 +1970,7 @@ s_pack_into(PyObject *self, PyObject *const *args, Py_ssize_t nargs) /* Check that negative offset is not crossing buffer boundary */ if (offset + buffer.len < 0) { - PyErr_Format(_structmodulestate_global->StructError, + PyErr_Format(state->StructError, "offset %zd out of range for %zd-byte buffer", offset, buffer.len); @@ -1973,7 +1986,7 @@ s_pack_into(PyObject *self, PyObject *const *args, Py_ssize_t nargs) assert(offset >= 0); assert(soself->s_size >= 0); - PyErr_Format(_structmodulestate_global->StructError, + PyErr_Format(state->StructError, "pack_into requires a buffer of at least %zu bytes for " "packing %zd bytes at offset %zd " "(actual buffer size is %zd)", @@ -1986,7 +1999,7 @@ s_pack_into(PyObject *self, PyObject *const *args, Py_ssize_t nargs) } /* Call the guts */ - if (s_pack_internal(soself, args, 2, (char*)buffer.buf + offset) != 0) { + if (s_pack_internal(soself, args, 2, (char*)buffer.buf + offset, state) != 0) { PyBuffer_Release(&buffer); return NULL; } @@ -2086,6 +2099,7 @@ static int cache_struct_converter(PyObject *fmt, PyStructObject **ptr) { PyObject * s_object; + _structmodulestate *state = _structmodulestate_global; if (fmt == NULL) { Py_DECREF(*ptr); @@ -2109,7 +2123,7 @@ cache_struct_converter(PyObject *fmt, PyStructObject **ptr) return 0; } - s_object = PyObject_CallOneArg(_structmodulestate_global->PyStructType, fmt); + s_object = PyObject_CallOneArg(state->PyStructType, fmt); if (s_object != NULL) { if (PyDict_GET_SIZE(cache) >= MAXCACHE) PyDict_Clear(cache); @@ -2322,7 +2336,7 @@ The variable struct.error is an exception raised on errors.\n"); static int _structmodule_traverse(PyObject *module, visitproc visit, void *arg) { - _structmodulestate *state = (_structmodulestate *)PyModule_GetState(module); + _structmodulestate *state = get_struct_state(module); if (state) { Py_VISIT(state->PyStructType); Py_VISIT(state->unpackiter_type); @@ -2334,7 +2348,7 @@ _structmodule_traverse(PyObject *module, visitproc visit, void *arg) static int _structmodule_clear(PyObject *module) { - _structmodulestate *state = (_structmodulestate *)PyModule_GetState(module); + _structmodulestate *state = get_struct_state(module); if (state) { Py_CLEAR(state->PyStructType); Py_CLEAR(state->unpackiter_type); @@ -2349,40 +2363,25 @@ _structmodule_free(void *module) _structmodule_clear((PyObject *)module); } -static struct PyModuleDef _structmodule = { - PyModuleDef_HEAD_INIT, - "_struct", - module_doc, - sizeof(_structmodulestate), - module_functions, - NULL, - _structmodule_traverse, - _structmodule_clear, - _structmodule_free, -}; - -PyMODINIT_FUNC -PyInit__struct(void) +static int +_structmodule_exec(PyObject *m) { - PyObject *m; - - m = PyModule_Create(&_structmodule); - if (m == NULL) - return NULL; + _structmodulestate *state = get_struct_state(m); - PyObject *PyStructType = PyType_FromSpec(&PyStructType_spec); - if (PyStructType == NULL) { - return NULL; + state->PyStructType = PyType_FromModuleAndSpec( + m, &PyStructType_spec, NULL); + if (state->PyStructType == NULL) { + return -1; + } + if (PyModule_AddType(m, (PyTypeObject *)state->PyStructType) < 0) { + return -1; } - Py_INCREF(PyStructType); - PyModule_AddObject(m, "Struct", PyStructType); - get_struct_state(m)->PyStructType = PyStructType; - PyObject *unpackiter_type = PyType_FromSpec(&unpackiter_type_spec); - if (unpackiter_type == NULL) { - return NULL; + state->unpackiter_type = PyType_FromModuleAndSpec( + m, &unpackiter_type_spec, NULL); + if (state->unpackiter_type == NULL) { + return -1; } - get_struct_state(m)->unpackiter_type = unpackiter_type; /* Check endian and swap in faster functions */ { @@ -2427,12 +2426,43 @@ PyInit__struct(void) } /* Add some symbolic constants to the module */ - PyObject *StructError = PyErr_NewException("struct.error", NULL, NULL); - if (StructError == NULL) + state->StructError = PyErr_NewException("struct.error", NULL, NULL); + if (state->StructError == NULL) { + return -1; + } + if (PyModule_AddObjectRef(m, "error", state->StructError) < 0) { + return -1; + } + + return 0; + +} + +static struct PyModuleDef _structmodule = { + PyModuleDef_HEAD_INIT, + "_struct", + module_doc, + sizeof(_structmodulestate), + module_functions, + NULL, + _structmodule_traverse, + _structmodule_clear, + _structmodule_free, +}; + +PyMODINIT_FUNC +PyInit__struct(void) +{ + PyObject *m; + + m = PyModule_Create(&_structmodule); + if (m == NULL) return NULL; - Py_INCREF(StructError); - PyModule_AddObject(m, "error", StructError); - get_struct_state(m)->StructError = StructError; + if (_structmodule_exec(m) < 0) { + Py_DECREF(m); + return NULL; + } return m; + } From a151e8c52f07e22a7ca53829d0d5f389c6cddab3 Mon Sep 17 00:00:00 2001 From: Christian Heimes Date: Thu, 19 Nov 2020 12:54:31 +0100 Subject: [PATCH 2/2] Move struct cache to module state, enable multiphase Signed-off-by: Christian Heimes --- ...2020-11-19-12-06-43.bpo-1635741.KEfZpn.rst | 2 +- Modules/_struct.c | 80 ++++++++++--------- Modules/clinic/_struct.c.h | 10 +-- 3 files changed, 47 insertions(+), 45 deletions(-) diff --git a/Misc/NEWS.d/next/C API/2020-11-19-12-06-43.bpo-1635741.KEfZpn.rst b/Misc/NEWS.d/next/C API/2020-11-19-12-06-43.bpo-1635741.KEfZpn.rst index ef6d7b8ba7cdd6..fc64757e00b3ac 100644 --- a/Misc/NEWS.d/next/C API/2020-11-19-12-06-43.bpo-1635741.KEfZpn.rst +++ b/Misc/NEWS.d/next/C API/2020-11-19-12-06-43.bpo-1635741.KEfZpn.rst @@ -1 +1 @@ -Prepare _struct extension module for multiphase initialization +Port _struct extension module to multiphase initialization (:pep:`489`) diff --git a/Modules/_struct.c b/Modules/_struct.c index 20e0386b7aa4c6..8dfcd882a444b9 100644 --- a/Modules/_struct.c +++ b/Modules/_struct.c @@ -15,6 +15,7 @@ class Struct "PyStructObject *" "&PyStructType" /*[clinic end generated code: output=da39a3ee5e6b4b0d input=9b032058a83ed7c3]*/ typedef struct { + PyObject *cache; PyObject *PyStructType; PyObject *unpackiter_type; PyObject *StructError; @@ -30,7 +31,6 @@ get_struct_state(PyObject *module) static struct PyModuleDef _structmodule; -#define _structmodulestate_global get_struct_state(PyState_FindModule(&_structmodule)) #define get_struct_state_structinst(self) \ (get_struct_state(_PyType_GetModuleByDef(Py_TYPE(self), &_structmodule))) #define get_struct_state_iterinst(self) \ @@ -103,12 +103,20 @@ class cache_struct_converter(CConverter): converter = 'cache_struct_converter' c_default = "NULL" + def parse_arg(self, argname, displayname): + return """ + if (!{converter}(module, {argname}, &{paramname})) {{{{ + goto exit; + }}}} + """.format(argname=argname, paramname=self.name, + converter=self.converter) + def cleanup(self): return "Py_XDECREF(%s);\n" % self.name [python start generated code]*/ -/*[python end generated code: output=da39a3ee5e6b4b0d input=49957cca130ffb63]*/ +/*[python end generated code: output=da39a3ee5e6b4b0d input=d6746621c2fb1a7d]*/ -static int cache_struct_converter(PyObject *, PyStructObject **); +static int cache_struct_converter(PyObject *, PyObject *, PyStructObject **); #include "clinic/_struct.c.h" @@ -2093,13 +2101,12 @@ static PyType_Spec PyStructType_spec = { /* ---- Standalone functions ---- */ #define MAXCACHE 100 -static PyObject *cache = NULL; static int -cache_struct_converter(PyObject *fmt, PyStructObject **ptr) +cache_struct_converter(PyObject *module, PyObject *fmt, PyStructObject **ptr) { PyObject * s_object; - _structmodulestate *state = _structmodulestate_global; + _structmodulestate *state = get_struct_state(module); if (fmt == NULL) { Py_DECREF(*ptr); @@ -2107,13 +2114,13 @@ cache_struct_converter(PyObject *fmt, PyStructObject **ptr) return 1; } - if (cache == NULL) { - cache = PyDict_New(); - if (cache == NULL) + if (state->cache == NULL) { + state->cache = PyDict_New(); + if (state->cache == NULL) return 0; } - s_object = PyDict_GetItemWithError(cache, fmt); + s_object = PyDict_GetItemWithError(state->cache, fmt); if (s_object != NULL) { Py_INCREF(s_object); *ptr = (PyStructObject *)s_object; @@ -2125,10 +2132,10 @@ cache_struct_converter(PyObject *fmt, PyStructObject **ptr) s_object = PyObject_CallOneArg(state->PyStructType, fmt); if (s_object != NULL) { - if (PyDict_GET_SIZE(cache) >= MAXCACHE) - PyDict_Clear(cache); + if (PyDict_GET_SIZE(state->cache) >= MAXCACHE) + PyDict_Clear(state->cache); /* Attempt to cache the result */ - if (PyDict_SetItem(cache, fmt, s_object) == -1) + if (PyDict_SetItem(state->cache, fmt, s_object) == -1) PyErr_Clear(); *ptr = (PyStructObject *)s_object; return Py_CLEANUP_SUPPORTED; @@ -2146,7 +2153,7 @@ static PyObject * _clearcache_impl(PyObject *module) /*[clinic end generated code: output=ce4fb8a7bf7cb523 input=463eaae04bab3211]*/ { - Py_CLEAR(cache); + Py_CLEAR(get_struct_state(module)->cache); Py_RETURN_NONE; } @@ -2174,7 +2181,7 @@ Return a bytes object containing the values v1, v2, ... packed according\n\ to the format string. See help(struct) for more on format strings."); static PyObject * -pack(PyObject *self, PyObject *const *args, Py_ssize_t nargs) +pack(PyObject *module, PyObject *const *args, Py_ssize_t nargs) { PyObject *s_object = NULL; PyObject *format, *result; @@ -2185,7 +2192,7 @@ pack(PyObject *self, PyObject *const *args, Py_ssize_t nargs) } format = args[0]; - if (!cache_struct_converter(format, (PyStructObject **)&s_object)) { + if (!cache_struct_converter(module, format, (PyStructObject **)&s_object)) { return NULL; } result = s_pack(s_object, args + 1, nargs - 1); @@ -2202,7 +2209,7 @@ that the offset is a required argument. See help(struct) for more\n\ on format strings."); static PyObject * -pack_into(PyObject *self, PyObject *const *args, Py_ssize_t nargs) +pack_into(PyObject *module, PyObject *const *args, Py_ssize_t nargs) { PyObject *s_object = NULL; PyObject *format, *result; @@ -2213,7 +2220,7 @@ pack_into(PyObject *self, PyObject *const *args, Py_ssize_t nargs) } format = args[0]; - if (!cache_struct_converter(format, (PyStructObject **)&s_object)) { + if (!cache_struct_converter(module, format, (PyStructObject **)&s_object)) { return NULL; } result = s_pack_into(s_object, args + 1, nargs - 1); @@ -2338,6 +2345,7 @@ _structmodule_traverse(PyObject *module, visitproc visit, void *arg) { _structmodulestate *state = get_struct_state(module); if (state) { + Py_VISIT(state->cache); Py_VISIT(state->PyStructType); Py_VISIT(state->unpackiter_type); Py_VISIT(state->StructError); @@ -2350,6 +2358,7 @@ _structmodule_clear(PyObject *module) { _structmodulestate *state = get_struct_state(module); if (state) { + Py_CLEAR(state->cache); Py_CLEAR(state->PyStructType); Py_CLEAR(state->unpackiter_type); Py_CLEAR(state->StructError); @@ -2435,34 +2444,27 @@ _structmodule_exec(PyObject *m) } return 0; - } +static PyModuleDef_Slot _structmodule_slots[] = { + {Py_mod_exec, _structmodule_exec}, + {0, NULL} +}; + static struct PyModuleDef _structmodule = { PyModuleDef_HEAD_INIT, - "_struct", - module_doc, - sizeof(_structmodulestate), - module_functions, - NULL, - _structmodule_traverse, - _structmodule_clear, - _structmodule_free, + .m_name = "_struct", + .m_doc = module_doc, + .m_size = sizeof(_structmodulestate), + .m_methods = module_functions, + .m_slots = _structmodule_slots, + .m_traverse = _structmodule_traverse, + .m_clear = _structmodule_clear, + .m_free = _structmodule_free, }; PyMODINIT_FUNC PyInit__struct(void) { - PyObject *m; - - m = PyModule_Create(&_structmodule); - if (m == NULL) - return NULL; - - if (_structmodule_exec(m) < 0) { - Py_DECREF(m); - return NULL; - } - return m; - + return PyModuleDef_Init(&_structmodule); } diff --git a/Modules/clinic/_struct.c.h b/Modules/clinic/_struct.c.h index 1cfaef3b7131e9..b0c1eb4587ae23 100644 --- a/Modules/clinic/_struct.c.h +++ b/Modules/clinic/_struct.c.h @@ -199,7 +199,7 @@ calcsize(PyObject *module, PyObject *arg) PyStructObject *s_object = NULL; Py_ssize_t _return_value; - if (!cache_struct_converter(arg, &s_object)) { + if (!cache_struct_converter(module, arg, &s_object)) { goto exit; } _return_value = calcsize_impl(module, s_object); @@ -241,7 +241,7 @@ unpack(PyObject *module, PyObject *const *args, Py_ssize_t nargs) if (!_PyArg_CheckPositional("unpack", nargs, 2, 2)) { goto exit; } - if (!cache_struct_converter(args[0], &s_object)) { + if (!cache_struct_converter(module, args[0], &s_object)) { goto exit; } if (PyObject_GetBuffer(args[1], &buffer, PyBUF_SIMPLE) != 0) { @@ -297,7 +297,7 @@ unpack_from(PyObject *module, PyObject *const *args, Py_ssize_t nargs, PyObject if (!args) { goto exit; } - if (!cache_struct_converter(args[0], &s_object)) { + if (!cache_struct_converter(module, args[0], &s_object)) { goto exit; } if (PyObject_GetBuffer(args[1], &buffer, PyBUF_SIMPLE) != 0) { @@ -364,7 +364,7 @@ iter_unpack(PyObject *module, PyObject *const *args, Py_ssize_t nargs) if (!_PyArg_CheckPositional("iter_unpack", nargs, 2, 2)) { goto exit; } - if (!cache_struct_converter(args[0], &s_object)) { + if (!cache_struct_converter(module, args[0], &s_object)) { goto exit; } buffer = args[1]; @@ -376,4 +376,4 @@ iter_unpack(PyObject *module, PyObject *const *args, Py_ssize_t nargs) return return_value; } -/*[clinic end generated code: output=8089792d8ed0c1be input=a9049054013a1b77]*/ +/*[clinic end generated code: output=a3d3cd900091cb1c input=a9049054013a1b77]*/