Skip to content

Commit df69e75

Browse files
authored
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__.
1 parent cc28ed2 commit df69e75

File tree

3 files changed

+69
-64
lines changed

3 files changed

+69
-64
lines changed

Lib/test/test_hashlib.py

-10
Original file line numberDiff line numberDiff line change
@@ -167,16 +167,6 @@ def hash_constructors(self):
167167
constructors = self.constructors_to_test.values()
168168
return itertools.chain.from_iterable(constructors)
169169

170-
@support.refcount_test
171-
@unittest.skipIf(c_hashlib is None, 'Require _hashlib module')
172-
def test_refleaks_in_hash___init__(self):
173-
gettotalrefcount = support.get_attribute(sys, 'gettotalrefcount')
174-
sha1_hash = c_hashlib.new('sha1')
175-
refs_before = gettotalrefcount()
176-
for i in range(100):
177-
sha1_hash.__init__('sha1')
178-
self.assertAlmostEqual(gettotalrefcount() - refs_before, 0, delta=10)
179-
180170
def test_hash_array(self):
181171
a = array.array("b", range(10))
182172
for cons in self.hash_constructors:
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
The _hashlib OpenSSL wrapper extension module is now PEP-384 compliant.

Modules/_hashopenssl.c

+68-54
Original file line numberDiff line numberDiff line change
@@ -46,21 +46,29 @@
4646
#define PY_OPENSSL_HAS_BLAKE2 1
4747
#endif
4848

49+
static PyModuleDef _hashlibmodule;
50+
51+
typedef struct {
52+
PyTypeObject *EVPtype;
53+
} _hashlibstate;
54+
55+
#define _hashlibstate(o) ((_hashlibstate *)PyModule_GetState(o))
56+
#define _hashlibstate_global ((_hashlibstate *)PyModule_GetState(PyState_FindModule(&_hashlibmodule)))
57+
58+
4959
typedef struct {
5060
PyObject_HEAD
5161
EVP_MD_CTX *ctx; /* OpenSSL message digest context */
5262
PyThread_type_lock lock; /* OpenSSL context lock */
5363
} EVPobject;
5464

5565

56-
static PyTypeObject EVPtype;
57-
5866
#include "clinic/_hashopenssl.c.h"
5967
/*[clinic input]
6068
module _hashlib
61-
class _hashlib.HASH "EVPobject *" "&EVPtype"
69+
class _hashlib.HASH "EVPobject *" "((_hashlibstate *)PyModule_GetState(module))->EVPtype"
6270
[clinic start generated code]*/
63-
/*[clinic end generated code: output=da39a3ee5e6b4b0d input=a881a5092eecad28]*/
71+
/*[clinic end generated code: output=da39a3ee5e6b4b0d input=1adf85e8eb2ab979]*/
6472

6573

6674
/* LCOV_EXCL_START */
@@ -231,7 +239,9 @@ py_digest_by_name(const char *name)
231239
static EVPobject *
232240
newEVPobject(void)
233241
{
234-
EVPobject *retval = (EVPobject *)PyObject_New(EVPobject, &EVPtype);
242+
EVPobject *retval = (EVPobject *)PyObject_New(
243+
EVPobject, _hashlibstate_global->EVPtype
244+
);
235245
if (retval == NULL) {
236246
return NULL;
237247
}
@@ -273,10 +283,12 @@ EVP_hash(EVPobject *self, const void *vp, Py_ssize_t len)
273283
static void
274284
EVP_dealloc(EVPobject *self)
275285
{
286+
PyTypeObject *tp = Py_TYPE(self);
276287
if (self->lock != NULL)
277288
PyThread_free_lock(self->lock);
278289
EVP_MD_CTX_free(self->ctx);
279290
PyObject_Del(self);
291+
Py_DECREF(tp);
280292
}
281293

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

504-
static PyTypeObject EVPtype = {
505-
PyVarObject_HEAD_INIT(NULL, 0)
516+
static PyType_Slot EVPtype_slots[] = {
517+
{Py_tp_dealloc, EVP_dealloc},
518+
{Py_tp_repr, EVP_repr},
519+
{Py_tp_doc, (char *)hashtype_doc},
520+
{Py_tp_methods, EVP_methods},
521+
{Py_tp_getset, EVP_getseters},
522+
{0, 0},
523+
};
524+
525+
static PyType_Spec EVPtype_spec = {
506526
"_hashlib.HASH", /*tp_name*/
507527
sizeof(EVPobject), /*tp_basicsize*/
508528
0, /*tp_itemsize*/
509-
/* methods */
510-
(destructor)EVP_dealloc, /*tp_dealloc*/
511-
0, /*tp_vectorcall_offset*/
512-
0, /*tp_getattr*/
513-
0, /*tp_setattr*/
514-
0, /*tp_as_async*/
515-
(reprfunc)EVP_repr, /*tp_repr*/
516-
0, /*tp_as_number*/
517-
0, /*tp_as_sequence*/
518-
0, /*tp_as_mapping*/
519-
0, /*tp_hash*/
520-
0, /*tp_call*/
521-
0, /*tp_str*/
522-
0, /*tp_getattro*/
523-
0, /*tp_setattro*/
524-
0, /*tp_as_buffer*/
525-
Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /*tp_flags*/
526-
hashtype_doc, /*tp_doc*/
527-
0, /*tp_traverse*/
528-
0, /*tp_clear*/
529-
0, /*tp_richcompare*/
530-
0, /*tp_weaklistoffset*/
531-
0, /*tp_iter*/
532-
0, /*tp_iternext*/
533-
EVP_methods, /* tp_methods */
534-
NULL, /* tp_members */
535-
EVP_getseters, /* tp_getset */
536-
0, /* tp_base */
537-
0, /* tp_dict */
538-
0, /* tp_descr_get */
539-
0, /* tp_descr_set */
540-
0, /* tp_dictoffset */
529+
Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,
530+
EVPtype_slots
541531
};
542532

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

11211110
/* Initialize this module. */
11221111

1112+
static int
1113+
hashlib_traverse(PyObject *m, visitproc visit, void *arg)
1114+
{
1115+
_hashlibstate *state = _hashlibstate(m);
1116+
Py_VISIT(state->EVPtype);
1117+
return 0;
1118+
}
1119+
1120+
static int
1121+
hashlib_clear(PyObject *m)
1122+
{
1123+
_hashlibstate *state = _hashlibstate(m);
1124+
Py_CLEAR(state->EVPtype);
1125+
return 0;
1126+
}
1127+
1128+
static void
1129+
hashlib_free(void *m)
1130+
{
1131+
hashlib_clear((PyObject *)m);
1132+
}
1133+
11231134

11241135
static struct PyModuleDef _hashlibmodule = {
11251136
PyModuleDef_HEAD_INIT,
11261137
"_hashlib",
11271138
NULL,
1128-
-1,
1139+
sizeof(_hashlibstate),
11291140
EVP_functions,
11301141
NULL,
1131-
NULL,
1132-
NULL,
1133-
NULL
1142+
hashlib_traverse,
1143+
hashlib_clear,
1144+
hashlib_free
11341145
};
11351146

11361147
PyMODINIT_FUNC
@@ -1144,19 +1155,21 @@ PyInit__hashlib(void)
11441155
ERR_load_crypto_strings();
11451156
#endif
11461157

1147-
/* TODO build EVP_functions openssl_* entries dynamically based
1148-
* on what hashes are supported rather than listing many
1149-
* but having some be unsupported. Only init appropriate
1150-
* constants. */
1151-
1152-
Py_TYPE(&EVPtype) = &PyType_Type;
1153-
if (PyType_Ready(&EVPtype) < 0)
1154-
return NULL;
1158+
m = PyState_FindModule(&_hashlibmodule);
1159+
if (m != NULL) {
1160+
Py_INCREF(m);
1161+
return m;
1162+
}
11551163

11561164
m = PyModule_Create(&_hashlibmodule);
11571165
if (m == NULL)
11581166
return NULL;
11591167

1168+
PyTypeObject *EVPtype = (PyTypeObject *)PyType_FromSpec(&EVPtype_spec);
1169+
if (EVPtype == NULL)
1170+
return NULL;
1171+
_hashlibstate(m)->EVPtype = EVPtype;
1172+
11601173
openssl_md_meth_names = generate_hash_name_list();
11611174
if (openssl_md_meth_names == NULL) {
11621175
Py_DECREF(m);
@@ -1167,8 +1180,9 @@ PyInit__hashlib(void)
11671180
return NULL;
11681181
}
11691182

1170-
Py_INCREF((PyObject *)&EVPtype);
1171-
PyModule_AddObject(m, "HASH", (PyObject *)&EVPtype);
1183+
Py_INCREF((PyObject *)_hashlibstate(m)->EVPtype);
1184+
PyModule_AddObject(m, "HASH", (PyObject *)_hashlibstate(m)->EVPtype);
11721185

1186+
PyState_AddModule(m, &_hashlibmodule);
11731187
return m;
11741188
}

0 commit comments

Comments
 (0)