From 63f102fe079ecb5cb7b921a1cf8bce4077a9d7e2 Mon Sep 17 00:00:00 2001 From: Mohamed Koubaa Date: Sun, 6 Sep 2020 05:09:51 -0500 Subject: [PATCH] bpo-1635741: Port _sha1, _sha512, _md5 to multiphase init (GH-21818) Port the _sha1, _sha512, and _md5 extension modules to multi-phase initialization API (PEP 489). --- ...2020-08-10-16-11-32.bpo-1635741.O0d3ym.rst | 2 + Modules/clinic/md5module.c.h | 21 +- Modules/clinic/sha1module.c.h | 21 +- Modules/clinic/sha512module.c.h | 21 +- Modules/md5module.c | 156 +++++++----- Modules/sha1module.c | 156 +++++++----- Modules/sha512module.c | 239 ++++++++++-------- 7 files changed, 362 insertions(+), 254 deletions(-) create mode 100644 Misc/NEWS.d/next/Core and Builtins/2020-08-10-16-11-32.bpo-1635741.O0d3ym.rst diff --git a/Misc/NEWS.d/next/Core and Builtins/2020-08-10-16-11-32.bpo-1635741.O0d3ym.rst b/Misc/NEWS.d/next/Core and Builtins/2020-08-10-16-11-32.bpo-1635741.O0d3ym.rst new file mode 100644 index 00000000000..12af3d01ed8 --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2020-08-10-16-11-32.bpo-1635741.O0d3ym.rst @@ -0,0 +1,2 @@ +Port the :mod:`_sha1`, :mod:`_sha512`, and :mod:`_md5` extension modules +to multi-phase initialization API (:pep:`489`). diff --git a/Modules/clinic/md5module.c.h b/Modules/clinic/md5module.c.h index c109f9efec6..4762f2800d4 100644 --- a/Modules/clinic/md5module.c.h +++ b/Modules/clinic/md5module.c.h @@ -9,15 +9,26 @@ PyDoc_STRVAR(MD5Type_copy__doc__, "Return a copy of the hash object."); #define MD5TYPE_COPY_METHODDEF \ - {"copy", (PyCFunction)MD5Type_copy, METH_NOARGS, MD5Type_copy__doc__}, + {"copy", (PyCFunction)(void(*)(void))MD5Type_copy, METH_METHOD|METH_FASTCALL|METH_KEYWORDS, MD5Type_copy__doc__}, static PyObject * -MD5Type_copy_impl(MD5object *self); +MD5Type_copy_impl(MD5object *self, PyTypeObject *cls); static PyObject * -MD5Type_copy(MD5object *self, PyObject *Py_UNUSED(ignored)) +MD5Type_copy(MD5object *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) { - return MD5Type_copy_impl(self); + PyObject *return_value = NULL; + static const char * const _keywords[] = { NULL}; + static _PyArg_Parser _parser = {":copy", _keywords, 0}; + + if (!_PyArg_ParseStackAndKeywords(args, nargs, kwnames, &_parser + )) { + goto exit; + } + return_value = MD5Type_copy_impl(self, cls); + +exit: + return return_value; } PyDoc_STRVAR(MD5Type_digest__doc__, @@ -115,4 +126,4 @@ skip_optional_kwonly: exit: return return_value; } -/*[clinic end generated code: output=dbe3abc60086f3ef input=a9049054013a1b77]*/ +/*[clinic end generated code: output=53ff7f22dbaaea36 input=a9049054013a1b77]*/ diff --git a/Modules/clinic/sha1module.c.h b/Modules/clinic/sha1module.c.h index fc37b1ab880..3a3ab58c123 100644 --- a/Modules/clinic/sha1module.c.h +++ b/Modules/clinic/sha1module.c.h @@ -9,15 +9,26 @@ PyDoc_STRVAR(SHA1Type_copy__doc__, "Return a copy of the hash object."); #define SHA1TYPE_COPY_METHODDEF \ - {"copy", (PyCFunction)SHA1Type_copy, METH_NOARGS, SHA1Type_copy__doc__}, + {"copy", (PyCFunction)(void(*)(void))SHA1Type_copy, METH_METHOD|METH_FASTCALL|METH_KEYWORDS, SHA1Type_copy__doc__}, static PyObject * -SHA1Type_copy_impl(SHA1object *self); +SHA1Type_copy_impl(SHA1object *self, PyTypeObject *cls); static PyObject * -SHA1Type_copy(SHA1object *self, PyObject *Py_UNUSED(ignored)) +SHA1Type_copy(SHA1object *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) { - return SHA1Type_copy_impl(self); + PyObject *return_value = NULL; + static const char * const _keywords[] = { NULL}; + static _PyArg_Parser _parser = {":copy", _keywords, 0}; + + if (!_PyArg_ParseStackAndKeywords(args, nargs, kwnames, &_parser + )) { + goto exit; + } + return_value = SHA1Type_copy_impl(self, cls); + +exit: + return return_value; } PyDoc_STRVAR(SHA1Type_digest__doc__, @@ -115,4 +126,4 @@ skip_optional_kwonly: exit: return return_value; } -/*[clinic end generated code: output=3ddd637ae17e14b3 input=a9049054013a1b77]*/ +/*[clinic end generated code: output=abf1ab2545cea5a2 input=a9049054013a1b77]*/ diff --git a/Modules/clinic/sha512module.c.h b/Modules/clinic/sha512module.c.h index b8185b62bb6..f1192d74f9a 100644 --- a/Modules/clinic/sha512module.c.h +++ b/Modules/clinic/sha512module.c.h @@ -9,15 +9,26 @@ PyDoc_STRVAR(SHA512Type_copy__doc__, "Return a copy of the hash object."); #define SHA512TYPE_COPY_METHODDEF \ - {"copy", (PyCFunction)SHA512Type_copy, METH_NOARGS, SHA512Type_copy__doc__}, + {"copy", (PyCFunction)(void(*)(void))SHA512Type_copy, METH_METHOD|METH_FASTCALL|METH_KEYWORDS, SHA512Type_copy__doc__}, static PyObject * -SHA512Type_copy_impl(SHAobject *self); +SHA512Type_copy_impl(SHAobject *self, PyTypeObject *cls); static PyObject * -SHA512Type_copy(SHAobject *self, PyObject *Py_UNUSED(ignored)) +SHA512Type_copy(SHAobject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) { - return SHA512Type_copy_impl(self); + PyObject *return_value = NULL; + static const char * const _keywords[] = { NULL}; + static _PyArg_Parser _parser = {":copy", _keywords, 0}; + + if (!_PyArg_ParseStackAndKeywords(args, nargs, kwnames, &_parser + )) { + goto exit; + } + return_value = SHA512Type_copy_impl(self, cls); + +exit: + return return_value; } PyDoc_STRVAR(SHA512Type_digest__doc__, @@ -166,4 +177,4 @@ skip_optional_kwonly: exit: return return_value; } -/*[clinic end generated code: output=bbfa72d8703c82b5 input=a9049054013a1b77]*/ +/*[clinic end generated code: output=9ff9f11937fabf35 input=a9049054013a1b77]*/ diff --git a/Modules/md5module.c b/Modules/md5module.c index e4d9db40f22..5cd4e945101 100644 --- a/Modules/md5module.c +++ b/Modules/md5module.c @@ -318,22 +318,32 @@ md5_done(struct md5_state *md5, unsigned char *out) * ------------------------------------------------------------------------ */ -static PyTypeObject MD5type; +typedef struct { + PyTypeObject* md5_type; +} MD5State; - -static MD5object * -newMD5object(void) +static inline MD5State* +md5_get_state(PyObject *module) { - return (MD5object *)PyObject_New(MD5object, &MD5type); + void *state = PyModule_GetState(module); + assert(state != NULL); + return (MD5State *)state; } +static MD5object * +newMD5object(MD5State * st) +{ + return (MD5object *)PyObject_New(MD5object, st->md5_type); +} /* Internal methods for a hash object */ static void MD5_dealloc(PyObject *ptr) { + PyTypeObject *tp = Py_TYPE(ptr); PyObject_Del(ptr); + Py_DECREF(tp); } @@ -342,16 +352,19 @@ MD5_dealloc(PyObject *ptr) /*[clinic input] MD5Type.copy + cls: defining_class + Return a copy of the hash object. [clinic start generated code]*/ static PyObject * -MD5Type_copy_impl(MD5object *self) -/*[clinic end generated code: output=596eb36852f02071 input=2c09e6d2493f3079]*/ +MD5Type_copy_impl(MD5object *self, PyTypeObject *cls) +/*[clinic end generated code: output=bf055e08244bf5ee input=d89087dcfb2a8620]*/ { - MD5object *newobj; + MD5State *st = PyType_GetModuleState(cls); - if ((newobj = newMD5object())==NULL) + MD5object *newobj; + if ((newobj = newMD5object(st))==NULL) return NULL; newobj->hash_state = self->hash_state; @@ -445,7 +458,6 @@ md5_get_digest_size(PyObject *self, void *closure) return PyLong_FromLong(MD5_DIGESTSIZE); } - static PyGetSetDef MD5_getseters[] = { {"block_size", (getter)MD5_get_block_size, NULL, @@ -462,40 +474,19 @@ static PyGetSetDef MD5_getseters[] = { {NULL} /* Sentinel */ }; -static PyTypeObject MD5type = { - PyVarObject_HEAD_INIT(NULL, 0) - "_md5.md5", /*tp_name*/ - sizeof(MD5object), /*tp_basicsize*/ - 0, /*tp_itemsize*/ - /* methods */ - MD5_dealloc, /*tp_dealloc*/ - 0, /*tp_vectorcall_offset*/ - 0, /*tp_getattr*/ - 0, /*tp_setattr*/ - 0, /*tp_as_async*/ - 0, /*tp_repr*/ - 0, /*tp_as_number*/ - 0, /*tp_as_sequence*/ - 0, /*tp_as_mapping*/ - 0, /*tp_hash*/ - 0, /*tp_call*/ - 0, /*tp_str*/ - 0, /*tp_getattro*/ - 0, /*tp_setattro*/ - 0, /*tp_as_buffer*/ - Py_TPFLAGS_DEFAULT, /*tp_flags*/ - 0, /*tp_doc*/ - 0, /*tp_traverse*/ - 0, /*tp_clear*/ - 0, /*tp_richcompare*/ - 0, /*tp_weaklistoffset*/ - 0, /*tp_iter*/ - 0, /*tp_iternext*/ - MD5_methods, /* tp_methods */ - NULL, /* tp_members */ - MD5_getseters, /* tp_getset */ +static PyType_Slot md5_type_slots[] = { + {Py_tp_dealloc, MD5_dealloc}, + {Py_tp_methods, MD5_methods}, + {Py_tp_getset, MD5_getseters}, + {0,0} }; +static PyType_Spec md5_type_spec = { + .name = "_md5.md5", + .basicsize = sizeof(MD5object), + .flags = Py_TPFLAGS_DEFAULT, + .slots = md5_type_slots +}; /* The single module-level function: new() */ @@ -519,7 +510,8 @@ _md5_md5_impl(PyObject *module, PyObject *string, int usedforsecurity) if (string) GET_BUFFER_VIEW_OR_ERROUT(string, &buf); - if ((new = newMD5object()) == NULL) { + MD5State *st = md5_get_state(module); + if ((new = newMD5object(st)) == NULL) { if (string) PyBuffer_Release(&buf); return NULL; @@ -549,37 +541,69 @@ static struct PyMethodDef MD5_functions[] = { {NULL, NULL} /* Sentinel */ }; +static int +_md5_traverse(PyObject *module, visitproc visit, void *arg) +{ + MD5State *state = md5_get_state(module); + Py_VISIT(state->md5_type); + return 0; +} + +static int +_md5_clear(PyObject *module) +{ + MD5State *state = md5_get_state(module); + Py_CLEAR(state->md5_type); + return 0; +} + +static void +_md5_free(void *module) +{ + _md5_clear((PyObject *)module); +} /* Initialize this module. */ +static int +md5_exec(PyObject *m) +{ + MD5State *st = md5_get_state(m); + + st->md5_type = (PyTypeObject *)PyType_FromModuleAndSpec( + m, &md5_type_spec, NULL); + + if (st->md5_type == NULL) { + return -1; + } + + Py_INCREF((PyObject *)st->md5_type); + if (PyModule_AddObject(m, "MD5Type", (PyObject *)st->md5_type) < 0) { + Py_DECREF(st->md5_type); + return -1; + } + + return 0; +} + +static PyModuleDef_Slot _md5_slots[] = { + {Py_mod_exec, md5_exec}, + {0, NULL} +}; + static struct PyModuleDef _md5module = { PyModuleDef_HEAD_INIT, - "_md5", - NULL, - -1, - MD5_functions, - NULL, - NULL, - NULL, - NULL + .m_name = "_md5", + .m_size = sizeof(MD5State), + .m_methods = MD5_functions, + .m_slots = _md5_slots, + .m_traverse = _md5_traverse, + .m_clear = _md5_clear, + .m_free = _md5_free, }; PyMODINIT_FUNC PyInit__md5(void) { - PyObject *m; - - Py_SET_TYPE(&MD5type, &PyType_Type); - if (PyType_Ready(&MD5type) < 0) { - return NULL; - } - - m = PyModule_Create(&_md5module); - if (m == NULL) { - return NULL; - } - - Py_INCREF((PyObject *)&MD5type); - PyModule_AddObject(m, "MD5Type", (PyObject *)&MD5type); - return m; + return PyModuleDef_Init(&_md5module); } diff --git a/Modules/sha1module.c b/Modules/sha1module.c index b0656d83b3a..c22437de256 100644 --- a/Modules/sha1module.c +++ b/Modules/sha1module.c @@ -295,13 +295,22 @@ sha1_done(struct sha1_state *sha1, unsigned char *out) * ------------------------------------------------------------------------ */ -static PyTypeObject SHA1type; +typedef struct { + PyTypeObject* sha1_type; +} SHA1State; +static inline SHA1State* +sha1_get_state(PyObject *module) +{ + void *state = PyModule_GetState(module); + assert(state != NULL); + return (SHA1State *)state; +} static SHA1object * -newSHA1object(void) +newSHA1object(SHA1State *st) { - return (SHA1object *)PyObject_New(SHA1object, &SHA1type); + return (SHA1object *)PyObject_New(SHA1object, st->sha1_type); } @@ -310,7 +319,9 @@ newSHA1object(void) static void SHA1_dealloc(PyObject *ptr) { + PyTypeObject *tp = Py_TYPE(ptr); PyObject_Del(ptr); + Py_DECREF(tp); } @@ -319,16 +330,19 @@ SHA1_dealloc(PyObject *ptr) /*[clinic input] SHA1Type.copy + cls: defining_class + Return a copy of the hash object. [clinic start generated code]*/ static PyObject * -SHA1Type_copy_impl(SHA1object *self) -/*[clinic end generated code: output=b4e001264620f02a input=b7eae10df6f89b36]*/ +SHA1Type_copy_impl(SHA1object *self, PyTypeObject *cls) +/*[clinic end generated code: output=b32d4461ce8bc7a7 input=6c22e66fcc34c58e]*/ { - SHA1object *newobj; + SHA1State *st = PyType_GetModuleState(cls); - if ((newobj = newSHA1object()) == NULL) + SHA1object *newobj; + if ((newobj = newSHA1object(st)) == NULL) return NULL; newobj->hash_state = self->hash_state; @@ -422,7 +436,6 @@ sha1_get_digest_size(PyObject *self, void *closure) return PyLong_FromLong(SHA1_DIGESTSIZE); } - static PyGetSetDef SHA1_getseters[] = { {"block_size", (getter)SHA1_get_block_size, NULL, @@ -439,40 +452,19 @@ static PyGetSetDef SHA1_getseters[] = { {NULL} /* Sentinel */ }; -static PyTypeObject SHA1type = { - PyVarObject_HEAD_INIT(NULL, 0) - "_sha1.sha1", /*tp_name*/ - sizeof(SHA1object), /*tp_basicsize*/ - 0, /*tp_itemsize*/ - /* methods */ - SHA1_dealloc, /*tp_dealloc*/ - 0, /*tp_vectorcall_offset*/ - 0, /*tp_getattr*/ - 0, /*tp_setattr*/ - 0, /*tp_as_async*/ - 0, /*tp_repr*/ - 0, /*tp_as_number*/ - 0, /*tp_as_sequence*/ - 0, /*tp_as_mapping*/ - 0, /*tp_hash*/ - 0, /*tp_call*/ - 0, /*tp_str*/ - 0, /*tp_getattro*/ - 0, /*tp_setattro*/ - 0, /*tp_as_buffer*/ - Py_TPFLAGS_DEFAULT, /*tp_flags*/ - 0, /*tp_doc*/ - 0, /*tp_traverse*/ - 0, /*tp_clear*/ - 0, /*tp_richcompare*/ - 0, /*tp_weaklistoffset*/ - 0, /*tp_iter*/ - 0, /*tp_iternext*/ - SHA1_methods, /* tp_methods */ - NULL, /* tp_members */ - SHA1_getseters, /* tp_getset */ +static PyType_Slot sha1_type_slots[] = { + {Py_tp_dealloc, SHA1_dealloc}, + {Py_tp_methods, SHA1_methods}, + {Py_tp_getset, SHA1_getseters}, + {0,0} }; +static PyType_Spec sha1_type_spec = { + .name = "_sha1.sha1", + .basicsize = sizeof(SHA1object), + .flags = Py_TPFLAGS_DEFAULT, + .slots = sha1_type_slots +}; /* The single module-level function: new() */ @@ -496,7 +488,8 @@ _sha1_sha1_impl(PyObject *module, PyObject *string, int usedforsecurity) if (string) GET_BUFFER_VIEW_OR_ERROUT(string, &buf); - if ((new = newSHA1object()) == NULL) { + SHA1State *st = sha1_get_state(module); + if ((new = newSHA1object(st)) == NULL) { if (string) PyBuffer_Release(&buf); return NULL; @@ -526,37 +519,72 @@ static struct PyMethodDef SHA1_functions[] = { {NULL, NULL} /* Sentinel */ }; +static int +_sha1_traverse(PyObject *module, visitproc visit, void *arg) +{ + SHA1State *state = sha1_get_state(module); + Py_VISIT(state->sha1_type); + return 0; +} + +static int +_sha1_clear(PyObject *module) +{ + SHA1State *state = sha1_get_state(module); + Py_CLEAR(state->sha1_type); + return 0; +} + +static void +_sha1_free(void *module) +{ + _sha1_clear((PyObject *)module); +} + +static int +_sha1_exec(PyObject *module) +{ + SHA1State* st = sha1_get_state(module); + + st->sha1_type = (PyTypeObject *)PyType_FromModuleAndSpec( + module, &sha1_type_spec, NULL); + + if (st->sha1_type == NULL) { + return -1; + } + + Py_INCREF(st->sha1_type); + if (PyModule_AddObject(module, + "SHA1Type", + (PyObject *)st->sha1_type) < 0) { + Py_DECREF(st->sha1_type); + return -1; + } + + return 0; +} + /* Initialize this module. */ +static PyModuleDef_Slot _sha1_slots[] = { + {Py_mod_exec, _sha1_exec}, + {0, NULL} +}; + static struct PyModuleDef _sha1module = { PyModuleDef_HEAD_INIT, - "_sha1", - NULL, - -1, - SHA1_functions, - NULL, - NULL, - NULL, - NULL + .m_name = "_sha1", + .m_size = sizeof(SHA1State), + .m_methods = SHA1_functions, + .m_slots = _sha1_slots, + .m_traverse = _sha1_traverse, + .m_clear = _sha1_clear, + .m_free = _sha1_free }; PyMODINIT_FUNC PyInit__sha1(void) { - PyObject *m; - - Py_SET_TYPE(&SHA1type, &PyType_Type); - if (PyType_Ready(&SHA1type) < 0) { - return NULL; - } - - m = PyModule_Create(&_sha1module); - if (m == NULL) { - return NULL; - } - - Py_INCREF((PyObject *)&SHA1type); - PyModule_AddObject(m, "SHA1Type", (PyObject *)&SHA1type); - return m; + return PyModuleDef_Init(&_sha1module); } diff --git a/Modules/sha512module.c b/Modules/sha512module.c index aa2aeedcc6c..725098def4d 100644 --- a/Modules/sha512module.c +++ b/Modules/sha512module.c @@ -422,20 +422,29 @@ sha512_final(unsigned char digest[SHA_DIGESTSIZE], SHAobject *sha_info) * ------------------------------------------------------------------------ */ -static PyTypeObject SHA384type; -static PyTypeObject SHA512type; +typedef struct { + PyTypeObject* sha384_type; + PyTypeObject* sha512_type; +} SHA512State; - -static SHAobject * -newSHA384object(void) +static inline SHA512State* +sha512_get_state(PyObject *module) { - return (SHAobject *)PyObject_New(SHAobject, &SHA384type); + void *state = PyModule_GetState(module); + assert(state != NULL); + return (SHA512State *)state; } static SHAobject * -newSHA512object(void) +newSHA384object(SHA512State *st) { - return (SHAobject *)PyObject_New(SHAobject, &SHA512type); + return (SHAobject *)PyObject_New(SHAobject, st->sha384_type); +} + +static SHAobject * +newSHA512object(SHA512State *st) +{ + return (SHAobject *)PyObject_New(SHAobject, st->sha512_type); } /* Internal methods for a hash object */ @@ -443,7 +452,9 @@ newSHA512object(void) static void SHA512_dealloc(PyObject *ptr) { + PyTypeObject *tp = Py_TYPE(ptr); PyObject_Del(ptr); + Py_DECREF(tp); } @@ -452,21 +463,27 @@ SHA512_dealloc(PyObject *ptr) /*[clinic input] SHA512Type.copy + cls: defining_class + Return a copy of the hash object. [clinic start generated code]*/ static PyObject * -SHA512Type_copy_impl(SHAobject *self) -/*[clinic end generated code: output=adea896ed3164821 input=9f5f31e6c457776a]*/ +SHA512Type_copy_impl(SHAobject *self, PyTypeObject *cls) +/*[clinic end generated code: output=85ea5b47837a08e6 input=f673a18f66527c90]*/ { SHAobject *newobj; + SHA512State *st = PyType_GetModuleState(cls); - if (Py_IS_TYPE((PyObject*)self, &SHA512type)) { - if ( (newobj = newSHA512object())==NULL) + if (Py_IS_TYPE((PyObject*)self, st->sha512_type)) { + if ( (newobj = newSHA512object(st))==NULL) { return NULL; - } else { - if ( (newobj = newSHA384object())==NULL) + } + } + else { + if ( (newobj = newSHA384object(st))==NULL) { return NULL; + } } SHAcopy(self, newobj); @@ -574,74 +591,37 @@ static PyMemberDef SHA_members[] = { {NULL} /* Sentinel */ }; -static PyTypeObject SHA384type = { - PyVarObject_HEAD_INIT(NULL, 0) - "_sha512.sha384", /*tp_name*/ - sizeof(SHAobject), /*tp_basicsize*/ - 0, /*tp_itemsize*/ - /* methods */ - SHA512_dealloc, /*tp_dealloc*/ - 0, /*tp_vectorcall_offset*/ - 0, /*tp_getattr*/ - 0, /*tp_setattr*/ - 0, /*tp_as_async*/ - 0, /*tp_repr*/ - 0, /*tp_as_number*/ - 0, /*tp_as_sequence*/ - 0, /*tp_as_mapping*/ - 0, /*tp_hash*/ - 0, /*tp_call*/ - 0, /*tp_str*/ - 0, /*tp_getattro*/ - 0, /*tp_setattro*/ - 0, /*tp_as_buffer*/ - Py_TPFLAGS_DEFAULT, /*tp_flags*/ - 0, /*tp_doc*/ - 0, /*tp_traverse*/ - 0, /*tp_clear*/ - 0, /*tp_richcompare*/ - 0, /*tp_weaklistoffset*/ - 0, /*tp_iter*/ - 0, /*tp_iternext*/ - SHA_methods, /* tp_methods */ - SHA_members, /* tp_members */ - SHA_getseters, /* tp_getset */ +static PyType_Slot sha512_sha384_type_slots[] = { + {Py_tp_dealloc, SHA512_dealloc}, + {Py_tp_methods, SHA_methods}, + {Py_tp_members, SHA_members}, + {Py_tp_getset, SHA_getseters}, + {0,0} }; -static PyTypeObject SHA512type = { - PyVarObject_HEAD_INIT(NULL, 0) - "_sha512.sha512", /*tp_name*/ - sizeof(SHAobject), /*tp_basicsize*/ - 0, /*tp_itemsize*/ - /* methods */ - SHA512_dealloc, /*tp_dealloc*/ - 0, /*tp_vectorcall_offset*/ - 0, /*tp_getattr*/ - 0, /*tp_setattr*/ - 0, /*tp_as_async*/ - 0, /*tp_repr*/ - 0, /*tp_as_number*/ - 0, /*tp_as_sequence*/ - 0, /*tp_as_mapping*/ - 0, /*tp_hash*/ - 0, /*tp_call*/ - 0, /*tp_str*/ - 0, /*tp_getattro*/ - 0, /*tp_setattro*/ - 0, /*tp_as_buffer*/ - Py_TPFLAGS_DEFAULT, /*tp_flags*/ - 0, /*tp_doc*/ - 0, /*tp_traverse*/ - 0, /*tp_clear*/ - 0, /*tp_richcompare*/ - 0, /*tp_weaklistoffset*/ - 0, /*tp_iter*/ - 0, /*tp_iternext*/ - SHA_methods, /* tp_methods */ - SHA_members, /* tp_members */ - SHA_getseters, /* tp_getset */ +static PyType_Spec sha512_sha384_type_spec = { + .name = "_sha512.sha384", + .basicsize = sizeof(SHAobject), + .flags = Py_TPFLAGS_DEFAULT, + .slots = sha512_sha384_type_slots }; +static PyType_Slot sha512_sha512_type_slots[] = { + {Py_tp_dealloc, SHA512_dealloc}, + {Py_tp_methods, SHA_methods}, + {Py_tp_members, SHA_members}, + {Py_tp_getset, SHA_getseters}, + {0,0} +}; + +// Using PyType_GetModuleState() on this type is safe since +// it cannot be subclassed: it does not have the Py_TPFLAGS_BASETYPE flag. +static PyType_Spec sha512_sha512_type_spec = { + .name = "_sha512.sha512", + .basicsize = sizeof(SHAobject), + .flags = Py_TPFLAGS_DEFAULT, + .slots = sha512_sha512_type_slots +}; /* The single module-level function: new() */ @@ -662,10 +642,12 @@ _sha512_sha512_impl(PyObject *module, PyObject *string, int usedforsecurity) SHAobject *new; Py_buffer buf; + SHA512State *st = sha512_get_state(module); + if (string) GET_BUFFER_VIEW_OR_ERROUT(string, &buf); - if ((new = newSHA512object()) == NULL) { + if ((new = newSHA512object(st)) == NULL) { if (string) PyBuffer_Release(&buf); return NULL; @@ -704,10 +686,12 @@ _sha512_sha384_impl(PyObject *module, PyObject *string, int usedforsecurity) SHAobject *new; Py_buffer buf; + SHA512State *st = sha512_get_state(module); + if (string) GET_BUFFER_VIEW_OR_ERROUT(string, &buf); - if ((new = newSHA384object()) == NULL) { + if ((new = newSHA384object(st)) == NULL) { if (string) PyBuffer_Release(&buf); return NULL; @@ -738,43 +722,80 @@ static struct PyMethodDef SHA_functions[] = { {NULL, NULL} /* Sentinel */ }; +static int +_sha512_traverse(PyObject *module, visitproc visit, void *arg) +{ + SHA512State *state = sha512_get_state(module); + Py_VISIT(state->sha384_type); + Py_VISIT(state->sha512_type); + return 0; +} + +static int +_sha512_clear(PyObject *module) +{ + SHA512State *state = sha512_get_state(module); + Py_CLEAR(state->sha384_type); + Py_CLEAR(state->sha512_type); + return 0; +} + +static void +_sha512_free(void *module) +{ + _sha512_clear((PyObject *)module); +} + /* Initialize this module. */ +static int +_sha512_exec(PyObject *m) +{ + SHA512State* st = sha512_get_state(m); + + st->sha384_type = (PyTypeObject *)PyType_FromModuleAndSpec( + m, &sha512_sha384_type_spec, NULL); + + st->sha512_type = (PyTypeObject *)PyType_FromModuleAndSpec( + m, &sha512_sha512_type_spec, NULL); + + if (st->sha384_type == NULL || st->sha512_type == NULL) { + return -1; + } + + Py_INCREF(st->sha384_type); + if (PyModule_AddObject(m, "SHA384Type", (PyObject *)st->sha384_type) < 0) { + Py_DECREF(st->sha384_type); + return -1; + } + + Py_INCREF(st->sha512_type); + if (PyModule_AddObject(m, "SHA384Type", (PyObject *)st->sha512_type) < 0) { + Py_DECREF(st->sha512_type); + return -1; + } + + return 0; +} + +static PyModuleDef_Slot _sha512_slots[] = { + {Py_mod_exec, _sha512_exec}, + {0, NULL} +}; static struct PyModuleDef _sha512module = { PyModuleDef_HEAD_INIT, - "_sha512", - NULL, - -1, - SHA_functions, - NULL, - NULL, - NULL, - NULL + .m_name = "_sha512", + .m_size = sizeof(SHA512State), + .m_methods = SHA_functions, + .m_slots = _sha512_slots, + .m_traverse = _sha512_traverse, + .m_clear = _sha512_clear, + .m_free = _sha512_free }; PyMODINIT_FUNC PyInit__sha512(void) { - PyObject *m; - - Py_SET_TYPE(&SHA384type, &PyType_Type); - if (PyType_Ready(&SHA384type) < 0) { - return NULL; - } - Py_SET_TYPE(&SHA512type, &PyType_Type); - if (PyType_Ready(&SHA512type) < 0) { - return NULL; - } - - m = PyModule_Create(&_sha512module); - if (m == NULL) { - return NULL; - } - - Py_INCREF((PyObject *)&SHA384type); - PyModule_AddObject(m, "SHA384Type", (PyObject *)&SHA384type); - Py_INCREF((PyObject *)&SHA512type); - PyModule_AddObject(m, "SHA512Type", (PyObject *)&SHA512type); - return m; + return PyModuleDef_Init(&_sha512module); }