Skip to content

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

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 4 commits into from
Sep 25, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 0 additions & 10 deletions Lib/test/test_hashlib.py
Original file line number Diff line number Diff line change
Expand Up @@ -167,16 +167,6 @@ def hash_constructors(self):
constructors = self.constructors_to_test.values()
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):
a = array.array("b", range(10))
for cons in self.hash_constructors:
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
The _hashlib OpenSSL wrapper extension module is now PEP-384 compliant.
122 changes: 68 additions & 54 deletions Modules/_hashopenssl.c
Original file line number Diff line number Diff line change
Expand Up @@ -46,21 +46,29 @@
#define PY_OPENSSL_HAS_BLAKE2 1
#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 {
PyObject_HEAD
EVP_MD_CTX *ctx; /* OpenSSL message digest context */
PyThread_type_lock lock; /* OpenSSL context lock */
} EVPobject;


static PyTypeObject EVPtype;

#include "clinic/_hashopenssl.c.h"
/*[clinic input]
module _hashlib
class _hashlib.HASH "EVPobject *" "&EVPtype"
class _hashlib.HASH "EVPobject *" "((_hashlibstate *)PyModule_GetState(module))->EVPtype"
[clinic start generated code]*/
/*[clinic end generated code: output=da39a3ee5e6b4b0d input=a881a5092eecad28]*/
/*[clinic end generated code: output=da39a3ee5e6b4b0d input=1adf85e8eb2ab979]*/


/* LCOV_EXCL_START */
Expand Down Expand Up @@ -231,7 +239,9 @@ py_digest_by_name(const char *name)
static EVPobject *
newEVPobject(void)
{
EVPobject *retval = (EVPobject *)PyObject_New(EVPobject, &EVPtype);
EVPobject *retval = (EVPobject *)PyObject_New(
EVPobject, _hashlibstate_global->EVPtype
);
if (retval == NULL) {
return NULL;
}
Expand Down Expand Up @@ -273,10 +283,12 @@ EVP_hash(EVPobject *self, const void *vp, Py_ssize_t len)
static void
EVP_dealloc(EVPobject *self)
{
PyTypeObject *tp = Py_TYPE(self);
if (self->lock != NULL)
PyThread_free_lock(self->lock);
EVP_MD_CTX_free(self->ctx);
PyObject_Del(self);
Py_DECREF(tp);
}

static int
Expand Down Expand Up @@ -501,46 +513,23 @@ PyDoc_STRVAR(hashtype_doc,
"name -- the hash algorithm being used by this object\n"
"digest_size -- number of bytes in this hashes output");

static PyTypeObject EVPtype = {
PyVarObject_HEAD_INIT(NULL, 0)
static PyType_Slot EVPtype_slots[] = {
{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*/
sizeof(EVPobject), /*tp_basicsize*/
0, /*tp_itemsize*/
/* methods */
(destructor)EVP_dealloc, /*tp_dealloc*/
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 */
Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,
EVPtype_slots
};

\
static PyObject *
EVPnew(const EVP_MD *digest,
const unsigned char *cp, Py_ssize_t len, int usedforsecurity)
Expand Down Expand Up @@ -1120,17 +1109,39 @@ static struct PyMethodDef EVP_functions[] = {

/* 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 = {
PyModuleDef_HEAD_INIT,
"_hashlib",
NULL,
-1,
sizeof(_hashlibstate),
EVP_functions,
NULL,
NULL,
NULL,
NULL
hashlib_traverse,
hashlib_clear,
hashlib_free
};

PyMODINIT_FUNC
Expand All @@ -1144,19 +1155,21 @@ PyInit__hashlib(void)
ERR_load_crypto_strings();
#endif

/* TODO build EVP_functions openssl_* entries dynamically based
* on what hashes are supported rather than listing many
* but having some be unsupported. Only init appropriate
* constants. */

Py_TYPE(&EVPtype) = &PyType_Type;
if (PyType_Ready(&EVPtype) < 0)
return NULL;
m = PyState_FindModule(&_hashlibmodule);
if (m != NULL) {
Py_INCREF(m);
return m;
}

m = PyModule_Create(&_hashlibmodule);
if (m == 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();
if (openssl_md_meth_names == NULL) {
Py_DECREF(m);
Expand All @@ -1167,8 +1180,9 @@ PyInit__hashlib(void)
return NULL;
}

Py_INCREF((PyObject *)&EVPtype);
PyModule_AddObject(m, "HASH", (PyObject *)&EVPtype);
Py_INCREF((PyObject *)_hashlibstate(m)->EVPtype);
PyModule_AddObject(m, "HASH", (PyObject *)_hashlibstate(m)->EVPtype);

PyState_AddModule(m, &_hashlibmodule);
return m;
}