Commit df69e75e authored by Christian Heimes's avatar Christian Heimes Committed by GitHub

bpo-38142: Updated _hashopenssl.c to be PEP 384 compliant (#16071)

* Updated _hashopenssl.c to be PEP 384 compliant
* Remove refleak test from test_hashlib. The updated type no longer accepts random arguments to __init__.
parent cc28ed24
...@@ -167,16 +167,6 @@ class HashLibTestCase(unittest.TestCase): ...@@ -167,16 +167,6 @@ class HashLibTestCase(unittest.TestCase):
constructors = self.constructors_to_test.values() constructors = self.constructors_to_test.values()
return itertools.chain.from_iterable(constructors) return itertools.chain.from_iterable(constructors)
@support.refcount_test
@unittest.skipIf(c_hashlib is None, 'Require _hashlib module')
def test_refleaks_in_hash___init__(self):
gettotalrefcount = support.get_attribute(sys, 'gettotalrefcount')
sha1_hash = c_hashlib.new('sha1')
refs_before = gettotalrefcount()
for i in range(100):
sha1_hash.__init__('sha1')
self.assertAlmostEqual(gettotalrefcount() - refs_before, 0, delta=10)
def test_hash_array(self): def test_hash_array(self):
a = array.array("b", range(10)) a = array.array("b", range(10))
for cons in self.hash_constructors: for cons in self.hash_constructors:
......
The _hashlib OpenSSL wrapper extension module is now PEP-384 compliant.
...@@ -46,6 +46,16 @@ ...@@ -46,6 +46,16 @@
#define PY_OPENSSL_HAS_BLAKE2 1 #define PY_OPENSSL_HAS_BLAKE2 1
#endif #endif
static PyModuleDef _hashlibmodule;
typedef struct {
PyTypeObject *EVPtype;
} _hashlibstate;
#define _hashlibstate(o) ((_hashlibstate *)PyModule_GetState(o))
#define _hashlibstate_global ((_hashlibstate *)PyModule_GetState(PyState_FindModule(&_hashlibmodule)))
typedef struct { typedef struct {
PyObject_HEAD PyObject_HEAD
EVP_MD_CTX *ctx; /* OpenSSL message digest context */ EVP_MD_CTX *ctx; /* OpenSSL message digest context */
...@@ -53,14 +63,12 @@ typedef struct { ...@@ -53,14 +63,12 @@ typedef struct {
} EVPobject; } EVPobject;
static PyTypeObject EVPtype;
#include "clinic/_hashopenssl.c.h" #include "clinic/_hashopenssl.c.h"
/*[clinic input] /*[clinic input]
module _hashlib module _hashlib
class _hashlib.HASH "EVPobject *" "&EVPtype" class _hashlib.HASH "EVPobject *" "((_hashlibstate *)PyModule_GetState(module))->EVPtype"
[clinic start generated code]*/ [clinic start generated code]*/
/*[clinic end generated code: output=da39a3ee5e6b4b0d input=a881a5092eecad28]*/ /*[clinic end generated code: output=da39a3ee5e6b4b0d input=1adf85e8eb2ab979]*/
/* LCOV_EXCL_START */ /* LCOV_EXCL_START */
...@@ -231,7 +239,9 @@ py_digest_by_name(const char *name) ...@@ -231,7 +239,9 @@ py_digest_by_name(const char *name)
static EVPobject * static EVPobject *
newEVPobject(void) newEVPobject(void)
{ {
EVPobject *retval = (EVPobject *)PyObject_New(EVPobject, &EVPtype); EVPobject *retval = (EVPobject *)PyObject_New(
EVPobject, _hashlibstate_global->EVPtype
);
if (retval == NULL) { if (retval == NULL) {
return NULL; return NULL;
} }
...@@ -273,10 +283,12 @@ EVP_hash(EVPobject *self, const void *vp, Py_ssize_t len) ...@@ -273,10 +283,12 @@ EVP_hash(EVPobject *self, const void *vp, Py_ssize_t len)
static void static void
EVP_dealloc(EVPobject *self) EVP_dealloc(EVPobject *self)
{ {
PyTypeObject *tp = Py_TYPE(self);
if (self->lock != NULL) if (self->lock != NULL)
PyThread_free_lock(self->lock); PyThread_free_lock(self->lock);
EVP_MD_CTX_free(self->ctx); EVP_MD_CTX_free(self->ctx);
PyObject_Del(self); PyObject_Del(self);
Py_DECREF(tp);
} }
static int static int
...@@ -501,46 +513,23 @@ PyDoc_STRVAR(hashtype_doc, ...@@ -501,46 +513,23 @@ PyDoc_STRVAR(hashtype_doc,
"name -- the hash algorithm being used by this object\n" "name -- the hash algorithm being used by this object\n"
"digest_size -- number of bytes in this hashes output"); "digest_size -- number of bytes in this hashes output");
static PyTypeObject EVPtype = { static PyType_Slot EVPtype_slots[] = {
PyVarObject_HEAD_INIT(NULL, 0) {Py_tp_dealloc, EVP_dealloc},
{Py_tp_repr, EVP_repr},
{Py_tp_doc, (char *)hashtype_doc},
{Py_tp_methods, EVP_methods},
{Py_tp_getset, EVP_getseters},
{0, 0},
};
static PyType_Spec EVPtype_spec = {
"_hashlib.HASH", /*tp_name*/ "_hashlib.HASH", /*tp_name*/
sizeof(EVPobject), /*tp_basicsize*/ sizeof(EVPobject), /*tp_basicsize*/
0, /*tp_itemsize*/ 0, /*tp_itemsize*/
/* methods */ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,
(destructor)EVP_dealloc, /*tp_dealloc*/ EVPtype_slots
0, /*tp_vectorcall_offset*/
0, /*tp_getattr*/
0, /*tp_setattr*/
0, /*tp_as_async*/
(reprfunc)EVP_repr, /*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 | Py_TPFLAGS_BASETYPE, /*tp_flags*/
hashtype_doc, /*tp_doc*/
0, /*tp_traverse*/
0, /*tp_clear*/
0, /*tp_richcompare*/
0, /*tp_weaklistoffset*/
0, /*tp_iter*/
0, /*tp_iternext*/
EVP_methods, /* tp_methods */
NULL, /* tp_members */
EVP_getseters, /* tp_getset */
0, /* tp_base */
0, /* tp_dict */
0, /* tp_descr_get */
0, /* tp_descr_set */
0, /* tp_dictoffset */
}; };
\
static PyObject * static PyObject *
EVPnew(const EVP_MD *digest, EVPnew(const EVP_MD *digest,
const unsigned char *cp, Py_ssize_t len, int usedforsecurity) const unsigned char *cp, Py_ssize_t len, int usedforsecurity)
...@@ -1120,17 +1109,39 @@ static struct PyMethodDef EVP_functions[] = { ...@@ -1120,17 +1109,39 @@ static struct PyMethodDef EVP_functions[] = {
/* Initialize this module. */ /* Initialize this module. */
static int
hashlib_traverse(PyObject *m, visitproc visit, void *arg)
{
_hashlibstate *state = _hashlibstate(m);
Py_VISIT(state->EVPtype);
return 0;
}
static int
hashlib_clear(PyObject *m)
{
_hashlibstate *state = _hashlibstate(m);
Py_CLEAR(state->EVPtype);
return 0;
}
static void
hashlib_free(void *m)
{
hashlib_clear((PyObject *)m);
}
static struct PyModuleDef _hashlibmodule = { static struct PyModuleDef _hashlibmodule = {
PyModuleDef_HEAD_INIT, PyModuleDef_HEAD_INIT,
"_hashlib", "_hashlib",
NULL, NULL,
-1, sizeof(_hashlibstate),
EVP_functions, EVP_functions,
NULL, NULL,
NULL, hashlib_traverse,
NULL, hashlib_clear,
NULL hashlib_free
}; };
PyMODINIT_FUNC PyMODINIT_FUNC
...@@ -1144,19 +1155,21 @@ PyInit__hashlib(void) ...@@ -1144,19 +1155,21 @@ PyInit__hashlib(void)
ERR_load_crypto_strings(); ERR_load_crypto_strings();
#endif #endif
/* TODO build EVP_functions openssl_* entries dynamically based m = PyState_FindModule(&_hashlibmodule);
* on what hashes are supported rather than listing many if (m != NULL) {
* but having some be unsupported. Only init appropriate Py_INCREF(m);
* constants. */ return m;
}
Py_TYPE(&EVPtype) = &PyType_Type;
if (PyType_Ready(&EVPtype) < 0)
return NULL;
m = PyModule_Create(&_hashlibmodule); m = PyModule_Create(&_hashlibmodule);
if (m == NULL) if (m == NULL)
return NULL; return NULL;
PyTypeObject *EVPtype = (PyTypeObject *)PyType_FromSpec(&EVPtype_spec);
if (EVPtype == NULL)
return NULL;
_hashlibstate(m)->EVPtype = EVPtype;
openssl_md_meth_names = generate_hash_name_list(); openssl_md_meth_names = generate_hash_name_list();
if (openssl_md_meth_names == NULL) { if (openssl_md_meth_names == NULL) {
Py_DECREF(m); Py_DECREF(m);
...@@ -1167,8 +1180,9 @@ PyInit__hashlib(void) ...@@ -1167,8 +1180,9 @@ PyInit__hashlib(void)
return NULL; return NULL;
} }
Py_INCREF((PyObject *)&EVPtype); Py_INCREF((PyObject *)_hashlibstate(m)->EVPtype);
PyModule_AddObject(m, "HASH", (PyObject *)&EVPtype); PyModule_AddObject(m, "HASH", (PyObject *)_hashlibstate(m)->EVPtype);
PyState_AddModule(m, &_hashlibmodule);
return m; return m;
} }
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment