Skip to content

Commit b213a79

Browse files
committed
extract _hashlib helpers into a separate directory
1 parent 754e7c9 commit b213a79

20 files changed

+246
-156
lines changed

Makefile.pre.in

Lines changed: 28 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1481,6 +1481,12 @@ $(LIBEXPAT_A): $(LIBEXPAT_OBJS)
14811481
-rm -f $@
14821482
$(AR) $(ARFLAGS) $@ $(LIBEXPAT_OBJS)
14831483

1484+
##########################################################################
1485+
# '_hashlib', '_hmac' and HACL*-based modules helpers
1486+
1487+
Modules/_hashlib/buffer.o: $(srcdir)/Modules/_hashlib/buffer.c $(srcdir)/Modules/_hashlib/buffer.h $(PYTHON_HEADERS)
1488+
$(CC) -c $(PY_STDMODULE_CFLAGS) $(CCSHARED) -o $@ $(srcdir)/Modules/_hashlib/buffer.c
1489+
14841490
##########################################################################
14851491
# HACL* library build
14861492
#
@@ -3323,22 +3329,31 @@ MODULE__CTYPES_TEST_DEPS=$(srcdir)/Modules/_ctypes/_ctypes_test_generated.c.h
33233329
MODULE__CTYPES_MALLOC_CLOSURE=@MODULE__CTYPES_MALLOC_CLOSURE@
33243330
MODULE__DECIMAL_DEPS=$(srcdir)/Modules/_decimal/docstrings.h @LIBMPDEC_INTERNAL@
33253331
MODULE__ELEMENTTREE_DEPS=$(srcdir)/Modules/pyexpat.c @LIBEXPAT_INTERNAL@
3326-
MODULE__HASHLIB_DEPS=$(srcdir)/Modules/hashlib.h
33273332
MODULE__IO_DEPS=$(srcdir)/Modules/_io/_iomodule.h
33283333

3334+
MODULE__HASHLIB_DEPS= \
3335+
$(srcdir)/Modules/_hashlib/buffer.h \
3336+
$(srcdir)/Modules/_hashlib/fetch.h \
3337+
$(srcdir)/Modules/_hashlib/hashlib.h \
3338+
$(srcdir)/Modules/_hashlib/mutex.h
3339+
3340+
MODULE__HASHLIB_LDEPS= \
3341+
$(srcdir)/Modules/_hashlib/buffer.o
3342+
33293343
# HACL*-based cryptographic primitives
3330-
MODULE__MD5_DEPS=$(srcdir)/Modules/hashlib.h $(LIBHACL_MD5_HEADERS) $(LIBHACL_MD5_LIB_@LIBHACL_LDEPS_LIBTYPE@)
3331-
MODULE__MD5_LDEPS=$(LIBHACL_MD5_LIB_@LIBHACL_LDEPS_LIBTYPE@)
3332-
MODULE__SHA1_DEPS=$(srcdir)/Modules/hashlib.h $(LIBHACL_SHA1_HEADERS) $(LIBHACL_SHA1_LIB_@LIBHACL_LDEPS_LIBTYPE@)
3333-
MODULE__SHA1_LDEPS=$(LIBHACL_SHA1_LIB_@LIBHACL_LDEPS_LIBTYPE@)
3334-
MODULE__SHA2_DEPS=$(srcdir)/Modules/hashlib.h $(LIBHACL_SHA2_HEADERS) $(LIBHACL_SHA2_LIB_@LIBHACL_LDEPS_LIBTYPE@)
3335-
MODULE__SHA2_LDEPS=$(LIBHACL_SHA2_LIB_@LIBHACL_LDEPS_LIBTYPE@)
3336-
MODULE__SHA3_DEPS=$(srcdir)/Modules/hashlib.h $(LIBHACL_SHA3_HEADERS) $(LIBHACL_SHA3_LIB_@LIBHACL_LDEPS_LIBTYPE@)
3337-
MODULE__SHA3_LDEPS=$(LIBHACL_SHA3_LIB_@LIBHACL_LDEPS_LIBTYPE@)
3338-
MODULE__BLAKE2_DEPS=$(srcdir)/Modules/hashlib.h $(LIBHACL_BLAKE2_HEADERS) $(LIBHACL_BLAKE2_LIB_@LIBHACL_LDEPS_LIBTYPE@)
3339-
MODULE__BLAKE2_LDEPS=$(LIBHACL_BLAKE2_LIB_@LIBHACL_LDEPS_LIBTYPE@)
3340-
MODULE__HMAC_DEPS=$(srcdir)/Modules/hashlib.h $(LIBHACL_HMAC_HEADERS) $(LIBHACL_HMAC_LIB_@LIBHACL_LDEPS_LIBTYPE@)
3341-
MODULE__HMAC_LDEPS=$(LIBHACL_HMAC_LIB_@LIBHACL_LDEPS_LIBTYPE@)
3344+
MODULE__MD5_DEPS=$(MODULE__HASHLIB_DEPS) $(LIBHACL_MD5_HEADERS) $(LIBHACL_MD5_LIB_@LIBHACL_LDEPS_LIBTYPE@)
3345+
MODULE__MD5_LDEPS=$(MODULE__HASHLIB_LDEPS) $(LIBHACL_MD5_LIB_@LIBHACL_LDEPS_LIBTYPE@)
3346+
MODULE__SHA1_DEPS=$(MODULE__HASHLIB_DEPS) $(LIBHACL_SHA1_HEADERS) $(LIBHACL_SHA1_LIB_@LIBHACL_LDEPS_LIBTYPE@)
3347+
MODULE__SHA1_LDEPS=$(MODULE__HASHLIB_LDEPS) $(LIBHACL_SHA1_LIB_@LIBHACL_LDEPS_LIBTYPE@)
3348+
MODULE__SHA2_DEPS=$(MODULE__HASHLIB_DEPS) $(LIBHACL_SHA2_HEADERS) $(LIBHACL_SHA2_LIB_@LIBHACL_LDEPS_LIBTYPE@)
3349+
MODULE__SHA2_LDEPS=$(MODULE__HASHLIB_LDEPS) $(LIBHACL_SHA2_LIB_@LIBHACL_LDEPS_LIBTYPE@)
3350+
MODULE__SHA3_DEPS=$(MODULE__HASHLIB_DEPS) $(LIBHACL_SHA3_HEADERS) $(LIBHACL_SHA3_LIB_@LIBHACL_LDEPS_LIBTYPE@)
3351+
MODULE__SHA3_LDEPS=$(MODULE__HASHLIB_LDEPS) $(LIBHACL_SHA3_LIB_@LIBHACL_LDEPS_LIBTYPE@)
3352+
MODULE__BLAKE2_DEPS=$(MODULE__HASHLIB_DEPS) $(LIBHACL_BLAKE2_HEADERS) $(LIBHACL_BLAKE2_LIB_@LIBHACL_LDEPS_LIBTYPE@)
3353+
MODULE__BLAKE2_LDEPS=$(MODULE__HASHLIB_LDEPS) $(LIBHACL_BLAKE2_LIB_@LIBHACL_LDEPS_LIBTYPE@)
3354+
3355+
MODULE__HMAC_DEPS=$(MODULE__HASHLIB_DEPS) $(LIBHACL_HMAC_HEADERS) $(LIBHACL_HMAC_LIB_@LIBHACL_LDEPS_LIBTYPE@)
3356+
MODULE__HMAC_LDEPS=$(MODULE__HASHLIB_LDEPS) $(LIBHACL_HMAC_LIB_@LIBHACL_LDEPS_LIBTYPE@)
33423357

33433358
MODULE__SOCKET_DEPS=$(srcdir)/Modules/socketmodule.h $(srcdir)/Modules/addrinfo.h $(srcdir)/Modules/getaddrinfo.c $(srcdir)/Modules/getnameinfo.c
33443359
MODULE__SSL_DEPS=$(srcdir)/Modules/_ssl.h $(srcdir)/Modules/_ssl/cert.c $(srcdir)/Modules/_ssl/debughelpers.c $(srcdir)/Modules/_ssl/misc.c $(srcdir)/Modules/_ssl_data_111.h $(srcdir)/Modules/_ssl_data_300.h $(srcdir)/Modules/socketmodule.h

Modules/_hashlib/buffer.c

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
#include "buffer.h"
2+
3+
int
4+
_Py_hashlib_data_argument(PyObject **res, PyObject *data, PyObject *string)
5+
{
6+
if (data != NULL && string == NULL) {
7+
// called as H(data) or H(data=...)
8+
*res = data;
9+
return 1;
10+
}
11+
else if (data == NULL && string != NULL) {
12+
// called as H(string=...)
13+
if (PyErr_WarnEx(PyExc_DeprecationWarning,
14+
"the 'string' keyword parameter is deprecated since "
15+
"Python 3.15 and slated for removal in Python 3.19; "
16+
"use the 'data' keyword parameter or pass the data "
17+
"to hash as a positional argument instead", 1) < 0)
18+
{
19+
*res = NULL;
20+
return -1;
21+
}
22+
*res = string;
23+
return 1;
24+
}
25+
else if (data == NULL && string == NULL) {
26+
// fast path when no data is given
27+
assert(!PyErr_Occurred());
28+
*res = NULL;
29+
return 0;
30+
}
31+
else {
32+
// called as H(data=..., string)
33+
*res = NULL;
34+
PyErr_SetString(PyExc_TypeError,
35+
"'data' and 'string' are mutually exclusive "
36+
"and support for 'string' keyword parameter "
37+
"is slated for removal in a future version.");
38+
return -1;
39+
}
40+
}

Modules/_hashlib/buffer.h

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
#ifndef _HASHLIB_BUFFER_H
2+
#define _HASHLIB_BUFFER_H
3+
4+
#include "Python.h"
5+
6+
/*
7+
* Given an buffer-like OBJ, fill in the buffer VIEW with the result
8+
* of PyObject_GetBuffer.
9+
*
10+
* On error, set an exception and execute the ERRACTION statements,
11+
* e.g. 'return NULL' or 'goto error'.
12+
*
13+
* Parameters
14+
*
15+
* OBJ An object supporting the buffer API.
16+
* VIEW A Py_buffer pointer to fill.
17+
* ERRACTION The statements to execute on error.
18+
*/
19+
#define GET_BUFFER_VIEW_OR_ERROR(OBJ, VIEW, ERRACTION) \
20+
do { \
21+
if (PyUnicode_Check((OBJ))) { \
22+
PyErr_SetString(PyExc_TypeError, \
23+
"strings must be encoded before hashing"); \
24+
ERRACTION; \
25+
} \
26+
if (!PyObject_CheckBuffer((OBJ))) { \
27+
PyErr_SetString(PyExc_TypeError, \
28+
"object supporting the buffer API required"); \
29+
ERRACTION; \
30+
} \
31+
if (PyObject_GetBuffer((OBJ), (VIEW), PyBUF_SIMPLE) == -1) { \
32+
ERRACTION; \
33+
} \
34+
if ((VIEW)->ndim > 1) { \
35+
PyErr_SetString(PyExc_BufferError, \
36+
"buffer must be one-dimensional"); \
37+
PyBuffer_Release((VIEW)); \
38+
ERRACTION; \
39+
} \
40+
} while(0)
41+
42+
/* Specialization of GET_BUFFER_VIEW_OR_ERROR() returning NULL on error. */
43+
#define GET_BUFFER_VIEW_OR_ERROUT(OBJ, VIEW) \
44+
GET_BUFFER_VIEW_OR_ERROR(OBJ, VIEW, return NULL)
45+
46+
PyAPI_FUNC(int)
47+
_Py_hashlib_data_argument(PyObject **res, PyObject *data, PyObject *string);
48+
49+
#endif // !_HASHLIB_BUFFER_H

Modules/_hashlib/fetch.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
/* Interface for fetching a message digest from a digest-like identifier. */
2+
3+
#ifndef _HASHLIB_FETCH_H
4+
#define _HASHLIB_FETCH_H
5+
6+
#endif // !_HASHLIB_FETCH_H

Modules/_hashlib/hashlib.h

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
/* Common code for use by all hashlib related modules. */
2+
3+
#ifndef _HASHLIB_HASHLIB_H
4+
#define _HASHLIB_HASHLIB_H
5+
6+
#include "buffer.h"
7+
#include "fetch.h"
8+
#include "mutex.h"
9+
10+
#endif // !_HASHLIB_HASHLIB_H

Modules/_hashlib/mutex.h

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
#ifndef _HASHLIB_MUTEX_H
2+
#define _HASHLIB_MUTEX_H
3+
4+
#include "Python.h"
5+
#include "pycore_lock.h" // PyMutex
6+
7+
/* TODO(gpshead): We should make this a module or class attribute
8+
* to allow the user to optimize based on the platform they're using. */
9+
#define HASHLIB_GIL_MINSIZE 2048
10+
11+
/*
12+
* Helper code to synchronize access to the hash object when the GIL is
13+
* released around a CPU consuming hashlib operation. All code paths that
14+
* access a mutable part of obj must be enclosed in an ENTER_HASHLIB /
15+
* LEAVE_HASHLIB block or explicitly acquire and release the lock inside
16+
* a PY_BEGIN / END_ALLOW_THREADS block if they wish to release the GIL for
17+
* an operation.
18+
*
19+
* These only drop the GIL if the lock acquisition itself is likely to
20+
* block. Thus the non-blocking acquire gating the GIL release for a
21+
* blocking lock acquisition. The intent of these macros is to surround
22+
* the assumed always "fast" operations that you aren't releasing the
23+
* GIL around. Otherwise use code similar to what you see in hash
24+
* function update() methods.
25+
*/
26+
27+
#define ENTER_HASHLIB(OBJ) \
28+
do { \
29+
if ((OBJ)->use_mutex) { \
30+
PyMutex_Lock(&(OBJ)->mutex); \
31+
} \
32+
} while (0)
33+
34+
#define LEAVE_HASHLIB(OBJ) \
35+
do { \
36+
if ((OBJ)->use_mutex) { \
37+
PyMutex_Unlock(&(OBJ)->mutex); \
38+
} \
39+
} while (0)
40+
41+
#ifdef Py_GIL_DISABLED
42+
#define HASHLIB_INIT_MUTEX(OBJ) \
43+
do { \
44+
(OBJ)->mutex = (PyMutex){0}; \
45+
(OBJ)->use_mutex = true; \
46+
} while (0)
47+
#else
48+
#define HASHLIB_INIT_MUTEX(OBJ) \
49+
do { \
50+
(OBJ)->mutex = (PyMutex){0}; \
51+
(OBJ)->use_mutex = false; \
52+
} while (0)
53+
#endif
54+
55+
#endif // !_HASHLIB_MUTEX_H

Modules/_hashopenssl.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@
2626
#include "pycore_hashtable.h"
2727
#include "pycore_strhex.h" // _Py_strhex()
2828
#include "pycore_pyatomic_ft_wrappers.h" // FT_ATOMIC_LOAD_PTR_RELAXED
29-
#include "hashlib.h"
29+
#include "_hashlib/hashlib.h"
3030

3131
/* EVP is the preferred interface to hashing in OpenSSL */
3232
#include <openssl/evp.h>

Modules/blake2module.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,10 +14,10 @@
1414
#endif
1515

1616
#include "Python.h"
17-
#include "hashlib.h"
17+
#include "pycore_moduleobject.h"
1818
#include "pycore_strhex.h" // _Py_strhex()
1919
#include "pycore_typeobject.h"
20-
#include "pycore_moduleobject.h"
20+
#include "_hashlib/hashlib.h"
2121

2222
// QUICK CPU AUTODETECTION
2323
//

Modules/hashlib.h

Lines changed: 0 additions & 116 deletions
This file was deleted.

Modules/hmacmodule.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@
4646

4747
#include <stdbool.h>
4848

49-
#include "hashlib.h"
49+
#include "_hashlib/hashlib.h"
5050

5151
// --- Reusable error messages ------------------------------------------------
5252

Modules/md5module.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@
2121
#endif
2222

2323
#include "Python.h"
24-
#include "hashlib.h"
24+
#include "_hashlib/hashlib.h"
2525

2626
/*[clinic input]
2727
module _md5

Modules/sha1module.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,9 +20,9 @@
2020
#endif
2121

2222
#include "Python.h"
23-
#include "hashlib.h"
2423
#include "pycore_strhex.h" // _Py_strhex()
2524
#include "pycore_typeobject.h" // _PyType_GetModuleState()
25+
#include "_hashlib/hashlib.h"
2626

2727
/*[clinic input]
2828
module _sha1

0 commit comments

Comments
 (0)