]> git.ipfire.org Git - thirdparty/Python/cpython.git/commitdiff
gh-132993: expose `HASHLIB_GIL_MINSIZE` to private extension modules (#132999)
authorBénédikt Tran <10796600+picnixz@users.noreply.github.com>
Sun, 27 Apr 2025 22:20:15 +0000 (00:20 +0200)
committerGitHub <noreply@github.com>
Sun, 27 Apr 2025 22:20:15 +0000 (22:20 +0000)
Lib/test/support/hashlib_helper.py
Lib/test/test_hashlib.py
Lib/test/test_hmac.py
Modules/_hashopenssl.c
Modules/blake2module.c
Modules/hmacmodule.c
Modules/md5module.c
Modules/sha1module.c
Modules/sha2module.c
Modules/sha3module.c

index 06fac410a5e20fd9333703eba5ba5f5bba35c807..5043f08dd93de65fbbfb115534c064938e684bce 100644 (file)
@@ -1,5 +1,6 @@
 import functools
 import hashlib
+import importlib
 import unittest
 from test.support.import_helper import import_module
 
@@ -100,3 +101,22 @@ def requires_openssl_hashdigest(digestname, *, usedforsecurity=True):
     def decorator(func_or_class):
         return _decorate_func_or_class(func_or_class, decorator_func)
     return decorator
+
+
+def find_gil_minsize(modules_names, default=2048):
+    """Get the largest GIL_MINSIZE value for the given cryptographic modules.
+
+    The valid module names are the following:
+
+    - _hashlib
+    - _md5, _sha1, _sha2, _sha3, _blake2
+    - _hmac
+    """
+    sizes = []
+    for module_name in modules_names:
+        try:
+            module = importlib.import_module(module_name)
+        except ImportError:
+            continue
+        sizes.append(getattr(module, '_GIL_MINSIZE', default))
+    return max(sizes, default=default)
index 6ae5c9303121bf8333ef7b001b45c9876c31635c..5e3356a02f31b66274c8e7cac56950fe91ecc730 100644 (file)
@@ -20,6 +20,7 @@ import unittest
 import warnings
 from test import support
 from test.support import _4G, bigmemtest
+from test.support import hashlib_helper
 from test.support.import_helper import import_fresh_module
 from test.support import requires_resource
 from test.support import threading_helper
@@ -911,10 +912,13 @@ class HashLibTestCase(unittest.TestCase):
 
     def test_gil(self):
         # Check things work fine with an input larger than the size required
-        # for multithreaded operation (which is hardwired to 2048).
-        gil_minsize = 2048
-
+        # for multithreaded operation. Currently, all cryptographic modules
+        # have the same constant value (2048) but in the future it might not
+        # be the case.
+        mods = ['_md5', '_sha1', '_sha2', '_sha3', '_blake2', '_hashlib']
+        gil_minsize = hashlib_helper.find_gil_minsize(mods)
         for cons in self.hash_constructors:
+            # constructors belong to one of the above modules
             m = cons(usedforsecurity=False)
             m.update(b'1')
             m.update(b'#' * gil_minsize)
@@ -923,6 +927,8 @@ class HashLibTestCase(unittest.TestCase):
             m = cons(b'x' * gil_minsize, usedforsecurity=False)
             m.update(b'1')
 
+    def test_sha256_gil(self):
+        gil_minsize = hashlib_helper.find_gil_minsize(['_sha2', '_hashlib'])
         m = hashlib.sha256()
         m.update(b'1')
         m.update(b'#' * gil_minsize)
index e9a465180e9ce19fd926970b3675153b6e3ffb2f..70c7943772249e5ef515192c2aa12189796c31e3 100644 (file)
@@ -1100,6 +1100,11 @@ class UpdateTestCaseMixin:
         """Create a HMAC object."""
         raise NotImplementedError
 
+    @property
+    def gil_minsize(self):
+        """Get the maximal input length for the GIL to be held."""
+        raise NotImplementedError
+
     def check_update(self, key, chunks):
         chunks = list(chunks)
         msg = b''.join(chunks)
@@ -1118,11 +1123,10 @@ class UpdateTestCaseMixin:
             self.check_update(key, [msg])
 
     def test_update_large(self):
-        HASHLIB_GIL_MINSIZE = 2048
-
+        gil_minsize = self.gil_minsize
         key = random.randbytes(16)
-        top = random.randbytes(HASHLIB_GIL_MINSIZE + 1)
-        bot = random.randbytes(HASHLIB_GIL_MINSIZE + 1)
+        top = random.randbytes(gil_minsize + 1)
+        bot = random.randbytes(gil_minsize + 1)
         self.check_update(key, [top, bot])
 
     def test_update_exceptions(self):
@@ -1132,12 +1136,16 @@ class UpdateTestCaseMixin:
                 self.assertRaises(TypeError, h.update, msg)
 
 
-@hashlib_helper.requires_hashdigest('sha256')
+@requires_builtin_sha2()
 class PyUpdateTestCase(PyModuleMixin, UpdateTestCaseMixin, unittest.TestCase):
 
     def HMAC(self, key, msg=None):
         return self.hmac.HMAC(key, msg, digestmod='sha256')
 
+    @property
+    def gil_minsize(self):
+        return sha2._GIL_MINSIZE
+
 
 @hashlib_helper.requires_openssl_hashdigest('sha256')
 class OpenSSLUpdateTestCase(UpdateTestCaseMixin, unittest.TestCase):
@@ -1145,6 +1153,10 @@ class OpenSSLUpdateTestCase(UpdateTestCaseMixin, unittest.TestCase):
     def HMAC(self, key, msg=None):
         return _hashlib.hmac_new(key, msg, digestmod='sha256')
 
+    @property
+    def gil_minsize(self):
+        return _hashlib._GIL_MINSIZE
+
 
 class BuiltinUpdateTestCase(BuiltinModuleMixin,
                             UpdateTestCaseMixin, unittest.TestCase):
@@ -1154,6 +1166,10 @@ class BuiltinUpdateTestCase(BuiltinModuleMixin,
         # are still built, making it possible to use SHA-2 hashes.
         return self.hmac.new(key, msg, digestmod='sha256')
 
+    @property
+    def gil_minsize(self):
+        return self.hmac._GIL_MINSIZE
+
 
 class CopyBaseTestCase:
 
index 756a8b70931baa047596bb5c9a61b714cc7a38bd..469a39cde7a2f7bbaca9c3d907cbbad313cbcc23 100644 (file)
@@ -2358,6 +2358,16 @@ hashlib_exception(PyObject *module)
     return 0;
 }
 
+static int
+hashlib_constants(PyObject *module)
+{
+    if (PyModule_AddIntConstant(module, "_GIL_MINSIZE",
+                                HASHLIB_GIL_MINSIZE) < 0)
+    {
+        return -1;
+    }
+    return 0;
+}
 
 static PyModuleDef_Slot hashlib_slots[] = {
     {Py_mod_exec, hashlib_init_hashtable},
@@ -2367,6 +2377,7 @@ static PyModuleDef_Slot hashlib_slots[] = {
     {Py_mod_exec, hashlib_md_meth_names},
     {Py_mod_exec, hashlib_init_constructors},
     {Py_mod_exec, hashlib_exception},
+    {Py_mod_exec, hashlib_constants},
     {Py_mod_multiple_interpreters, Py_MOD_PER_INTERPRETER_GIL_SUPPORTED},
     {Py_mod_gil, Py_MOD_GIL_NOT_USED},
     {0, NULL}
index 0b0642c1e04e5aecd1d76fae050aefe7f093bea0..f9acc57f1b2fa3d5963208e28267c7914cddccaf 100644 (file)
@@ -229,6 +229,8 @@ blake2_exec(PyObject *m)
     // good a place as any to probe the CPU flags.
     detect_cpu_features(&st->flags);
 
+    ADD_INT_CONST("_GIL_MINSIZE", HASHLIB_GIL_MINSIZE);
+
     st->blake2b_type = (PyTypeObject *)PyType_FromModuleAndSpec(
         m, &blake2b_type_spec, NULL);
 
index f75854c6ef5c91c360beb1096ce1a3efe7159fdb..76079a7679426befa60e7848c576dd5454a2e74c 100644 (file)
@@ -1679,6 +1679,20 @@ hmacmodule_init_strings(hmacmodule_state *state)
     return 0;
 }
 
+static int
+hmacmodule_init_globals(PyObject *module, hmacmodule_state *state)
+{
+#define ADD_INT_CONST(NAME, VALUE)                                  \
+    do {                                                            \
+        if (PyModule_AddIntConstant(module, (NAME), (VALUE)) < 0) { \
+            return -1;                                              \
+        }                                                           \
+    } while (0)
+    ADD_INT_CONST("_GIL_MINSIZE", HASHLIB_GIL_MINSIZE);
+#undef ADD_INT_CONST
+    return 0;
+}
+
 static void
 hmacmodule_init_cpu_features(hmacmodule_state *state)
 {
@@ -1769,6 +1783,9 @@ hmacmodule_exec(PyObject *module)
     if (hmacmodule_init_strings(state) < 0) {
         return -1;
     }
+    if (hmacmodule_init_globals(module, state) < 0) {
+        return -1;
+    }
     hmacmodule_init_cpu_features(state);
     return 0;
 }
index bb5107700235e47af2d7c318972cc9fabe465cbc..c36eb41d4d201e96e6454f64063cc26465fb2ac6 100644 (file)
@@ -370,6 +370,9 @@ md5_exec(PyObject *m)
     if (PyModule_AddObjectRef(m, "MD5Type", (PyObject *)st->md5_type) < 0) {
         return -1;
     }
+    if (PyModule_AddIntConstant(m, "_GIL_MINSIZE", HASHLIB_GIL_MINSIZE) < 0) {
+        return -1;
+    }
 
     return 0;
 }
@@ -383,14 +386,14 @@ static PyModuleDef_Slot _md5_slots[] = {
 
 
 static struct PyModuleDef _md5module = {
-        PyModuleDef_HEAD_INIT,
-        .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,
+    PyModuleDef_HEAD_INIT,
+    .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
index 98948bcc570a9dab66656d3549b5b2ec678a273e..f4a00cdb42215670fbbe20936f635973cc8ad7cc 100644 (file)
@@ -362,8 +362,15 @@ _sha1_exec(PyObject *module)
     st->sha1_type = (PyTypeObject *)PyType_FromModuleAndSpec(
         module, &sha1_type_spec, NULL);
     if (PyModule_AddObjectRef(module,
-                           "SHA1Type",
-                           (PyObject *)st->sha1_type) < 0) {
+                              "SHA1Type",
+                              (PyObject *)st->sha1_type) < 0)
+    {
+        return -1;
+    }
+    if (PyModule_AddIntConstant(module,
+                                "_GIL_MINSIZE",
+                                HASHLIB_GIL_MINSIZE) < 0)
+    {
         return -1;
     }
 
@@ -381,14 +388,14 @@ static PyModuleDef_Slot _sha1_slots[] = {
 };
 
 static struct PyModuleDef _sha1module = {
-        PyModuleDef_HEAD_INIT,
-        .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
+    PyModuleDef_HEAD_INIT,
+    .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
index e35bbb8a4ce6df4b8e7b3c2b7938b749a7e980de..e88d7cb2d456bf0de9bc55c49a8d2b01eb12ef4f 100644 (file)
@@ -894,6 +894,13 @@ static int sha2_exec(PyObject *module)
         return -1;
     }
 
+    if (PyModule_AddIntConstant(module,
+                                "_GIL_MINSIZE",
+                                HASHLIB_GIL_MINSIZE) < 0)
+    {
+        return -1;
+    }
+
     return 0;
 }
 
index e4109b53eda6fe6b8aa13a3b9a7e3838f8704784..a7edf5c66a1e76e80cf818ac2356ca1bb697b0a8 100644 (file)
@@ -639,8 +639,10 @@ _sha3_exec(PyObject *m)
     init_sha3type(shake_256_type, SHAKE256_spec);
 #undef init_sha3type
 
-    if (PyModule_AddStringConstant(m, "implementation",
-                                   "HACL") < 0) {
+    if (PyModule_AddStringConstant(m, "implementation", "HACL") < 0) {
+        return -1;
+    }
+    if (PyModule_AddIntConstant(m, "_GIL_MINSIZE", HASHLIB_GIL_MINSIZE) < 0) {
         return -1;
     }