]> git.ipfire.org Git - thirdparty/Python/cpython.git/commitdiff
[3.13] gh-116946: fully implement GC protocol for `_hashlib` objects (GH-138289)...
authorBénédikt Tran <10796600+picnixz@users.noreply.github.com>
Mon, 1 Sep 2025 10:23:28 +0000 (12:23 +0200)
committerGitHub <noreply@github.com>
Mon, 1 Sep 2025 10:23:28 +0000 (12:23 +0200)
(cherry picked from commit 6f1dd9551a69c8c76d066a04e94db6dbc6c7597c)

Modules/_hashopenssl.c

index 5e4783395f4f48306665e50b35b51acd99349a88..ede9ca683adf2f2ba481e56f38023b3e6493b6ca 100644 (file)
@@ -282,6 +282,8 @@ typedef struct {
     PyMutex mutex;  /* OpenSSL context lock */
 } EVPobject;
 
+#define EVPobject_CAST(op)  ((EVPobject *)(op))
+
 typedef struct {
     PyObject_HEAD
     HMAC_CTX *ctx;            /* OpenSSL hmac context */
@@ -290,6 +292,8 @@ typedef struct {
     PyMutex mutex;  /* HMAC context lock */
 } HMACobject;
 
+#define HMACobject_CAST(op) ((HMACobject *)(op))
+
 #include "clinic/_hashopenssl.c.h"
 /*[clinic input]
 module _hashlib
@@ -497,7 +501,9 @@ py_digest_by_digestmod(PyObject *module, PyObject *digestmod, enum Py_hash_type
 static EVPobject *
 newEVPobject(PyTypeObject *type)
 {
-    EVPobject *retval = (EVPobject *)PyObject_New(EVPobject, type);
+    assert(type != NULL);
+    assert(type->tp_alloc != NULL);
+    EVPobject *retval = (EVPobject *)type->tp_alloc(type, 0);
     if (retval == NULL) {
         return NULL;
     }
@@ -536,14 +542,23 @@ EVP_hash(EVPobject *self, const void *vp, Py_ssize_t len)
 /* Internal methods for a hash object */
 
 static void
-EVP_dealloc(EVPobject *self)
+EVP_dealloc(PyObject *op)
 {
-    PyTypeObject *tp = Py_TYPE(self);
+    PyTypeObject *tp = Py_TYPE(op);
+    PyObject_GC_UnTrack(op);
+    EVPobject *self = EVPobject_CAST(op);
     EVP_MD_CTX_free(self->ctx);
-    PyObject_Free(self);
+    tp->tp_free(self);
     Py_DECREF(tp);
 }
 
+static int
+EVP_traverse(PyObject *op, visitproc visit, void *arg)
+{
+    Py_VISIT(Py_TYPE(op));
+    return 0;
+}
+
 static int
 locked_EVP_MD_CTX_copy(EVP_MD_CTX *new_ctx_p, EVPobject *self)
 {
@@ -781,6 +796,7 @@ PyDoc_STRVAR(hashtype_doc,
 
 static PyType_Slot EVPtype_slots[] = {
     {Py_tp_dealloc, EVP_dealloc},
+    {Py_tp_traverse, EVP_traverse},
     {Py_tp_repr, EVP_repr},
     {Py_tp_doc, (char *)hashtype_doc},
     {Py_tp_methods, EVP_methods},
@@ -789,11 +805,16 @@ static PyType_Slot EVPtype_slots[] = {
 };
 
 static PyType_Spec EVPtype_spec = {
-    "_hashlib.HASH",    /*tp_name*/
-    sizeof(EVPobject),  /*tp_basicsize*/
-    0,                  /*tp_itemsize*/
-    Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_DISALLOW_INSTANTIATION | Py_TPFLAGS_IMMUTABLETYPE,
-    EVPtype_slots
+    .name = "_hashlib.HASH",
+    .basicsize = sizeof(EVPobject),
+    .flags = (
+        Py_TPFLAGS_DEFAULT
+        | Py_TPFLAGS_BASETYPE
+        | Py_TPFLAGS_DISALLOW_INSTANTIATION
+        | Py_TPFLAGS_IMMUTABLETYPE
+        | Py_TPFLAGS_HAVE_GC
+    ),
+    .slots = EVPtype_slots
 };
 
 #ifdef PY_OPENSSL_HAS_SHAKE
@@ -934,6 +955,8 @@ PyDoc_STRVAR(hashxoftype_doc,
 "digest_size -- number of bytes in this hashes output");
 
 static PyType_Slot EVPXOFtype_slots[] = {
+    {Py_tp_dealloc, EVP_dealloc},
+    {Py_tp_traverse, EVP_traverse},
     {Py_tp_doc, (char *)hashxoftype_doc},
     {Py_tp_methods, EVPXOF_methods},
     {Py_tp_getset, EVPXOF_getseters},
@@ -941,11 +964,16 @@ static PyType_Slot EVPXOFtype_slots[] = {
 };
 
 static PyType_Spec EVPXOFtype_spec = {
-    "_hashlib.HASHXOF",    /*tp_name*/
-    sizeof(EVPobject),  /*tp_basicsize*/
-    0,                  /*tp_itemsize*/
-    Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_DISALLOW_INSTANTIATION | Py_TPFLAGS_IMMUTABLETYPE,
-    EVPXOFtype_slots
+    .name = "_hashlib.HASHXOF",
+    .basicsize = sizeof(EVPobject),
+    .flags = (
+        Py_TPFLAGS_DEFAULT
+        | Py_TPFLAGS_BASETYPE
+        | Py_TPFLAGS_DISALLOW_INSTANTIATION
+        | Py_TPFLAGS_IMMUTABLETYPE
+        | Py_TPFLAGS_HAVE_GC
+    ),
+    .slots = EVPXOFtype_slots
 };
 
 
@@ -1659,7 +1687,8 @@ _hashlib_hmac_new_impl(PyObject *module, Py_buffer *key, PyObject *msg_obj,
     }
 
     _hashlibstate *state = get_hashlib_state(module);
-    self = PyObject_New(HMACobject, state->HMACtype);
+    assert(state->HMACtype != NULL);
+    self = (HMACobject *)state->HMACtype->tp_alloc(state->HMACtype, 0);
     if (self == NULL) {
         goto error;
     }
@@ -1764,7 +1793,8 @@ _hashlib_HMAC_copy_impl(HMACobject *self)
         return NULL;
     }
 
-    retval = PyObject_New(HMACobject, Py_TYPE(self));
+    PyTypeObject *type = Py_TYPE(self);
+    retval = (HMACobject *)type->tp_alloc(type, 0);
     if (retval == NULL) {
         HMAC_CTX_free(ctx);
         return NULL;
@@ -1776,17 +1806,26 @@ _hashlib_HMAC_copy_impl(HMACobject *self)
 }
 
 static void
-_hmac_dealloc(HMACobject *self)
+_hmac_dealloc(PyObject *op)
 {
-    PyTypeObject *tp = Py_TYPE(self);
+    PyTypeObject *tp = Py_TYPE(op);
+    PyObject_GC_UnTrack(op);
+    HMACobject *self = HMACobject_CAST(op);
     if (self->ctx != NULL) {
         HMAC_CTX_free(self->ctx);
         self->ctx = NULL;
     }
-    PyObject_Free(self);
+    tp->tp_free(self);
     Py_DECREF(tp);
 }
 
+static int
+_hmac_traverse(PyObject *op, visitproc visit, void *arg)
+{
+    Py_VISIT(Py_TYPE(op));
+    return 0;
+}
+
 static PyObject *
 _hmac_repr(HMACobject *self)
 {
@@ -1954,16 +1993,22 @@ digest_size -- number of bytes in digest() output\n");
 static PyType_Slot HMACtype_slots[] = {
     {Py_tp_doc, (char *)hmactype_doc},
     {Py_tp_repr, (reprfunc)_hmac_repr},
-    {Py_tp_dealloc,(destructor)_hmac_dealloc},
+    {Py_tp_dealloc, _hmac_dealloc},
+    {Py_tp_traverse, _hmac_traverse},
     {Py_tp_methods, HMAC_methods},
     {Py_tp_getset, HMAC_getset},
     {0, NULL}
 };
 
 PyType_Spec HMACtype_spec = {
-    "_hashlib.HMAC",    /* name */
-    sizeof(HMACobject),     /* basicsize */
-    .flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_DISALLOW_INSTANTIATION | Py_TPFLAGS_IMMUTABLETYPE,
+    .name = "_hashlib.HMAC",
+    .basicsize = sizeof(HMACobject),
+    .flags = (
+        Py_TPFLAGS_DEFAULT
+        | Py_TPFLAGS_DISALLOW_INSTANTIATION
+        | Py_TPFLAGS_IMMUTABLETYPE
+        | Py_TPFLAGS_HAVE_GC
+    ),
     .slots = HMACtype_slots,
 };