diff --git a/Makefile.pre.in b/Makefile.pre.in index d3d24a13898d99..f076954905b1a8 100644 --- a/Makefile.pre.in +++ b/Makefile.pre.in @@ -3461,7 +3461,7 @@ MODULE__CTYPES_DEPS=$(srcdir)/Modules/_ctypes/ctypes.h MODULE__CTYPES_TEST_DEPS=$(srcdir)/Modules/_ctypes/_ctypes_test_generated.c.h MODULE__CTYPES_MALLOC_CLOSURE=@MODULE__CTYPES_MALLOC_CLOSURE@ MODULE__ELEMENTTREE_DEPS=$(srcdir)/Modules/pyexpat.c @LIBEXPAT_INTERNAL@ -MODULE__HASHLIB_DEPS=$(srcdir)/Modules/hashlib.h +MODULE__HASHLIB_DEPS=$(srcdir)/Modules/hashlib.h $(srcdir)/Modules/_openssl_mem.h MODULE__IO_DEPS=$(srcdir)/Modules/_io/_iomodule.h MODULE__REMOTE_DEBUGGING_DEPS=$(srcdir)/Modules/_remote_debugging/_remote_debugging.h $(srcdir)/Modules/_remote_debugging/gc_stats.h @@ -3480,7 +3480,7 @@ MODULE__HMAC_DEPS=$(srcdir)/Modules/hashlib.h $(LIBHACL_HMAC_HEADERS) $(LIBHACL_ MODULE__HMAC_LDEPS=$(LIBHACL_HMAC_LIB_@LIBHACL_LDEPS_LIBTYPE@) MODULE__SOCKET_DEPS=$(srcdir)/Modules/socketmodule.h $(srcdir)/Modules/addrinfo.h $(srcdir)/Modules/getaddrinfo.c $(srcdir)/Modules/getnameinfo.c -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 +MODULE__SSL_DEPS=$(srcdir)/Modules/_ssl.h $(srcdir)/Modules/_openssl_mem.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 MODULE__TESTCAPI_DEPS=$(srcdir)/Modules/_testcapi/parts.h $(srcdir)/Modules/_testcapi/util.h MODULE__TESTLIMITEDCAPI_DEPS=$(srcdir)/Modules/_testlimitedcapi/testcapi_long.h $(srcdir)/Modules/_testlimitedcapi/parts.h $(srcdir)/Modules/_testlimitedcapi/util.h MODULE__TESTINTERNALCAPI_DEPS=$(srcdir)/Modules/_testinternalcapi/parts.h $(srcdir)/Python/ceval.h $(srcdir)/Modules/_testinternalcapi/test_targets.h $(srcdir)/Modules/_testinternalcapi/test_cases.c.h diff --git a/Misc/NEWS.d/next/Library/2026-08-22-10-30-00.gh-issue-156228.k3Rmxw.rst b/Misc/NEWS.d/next/Library/2026-08-22-10-30-00.gh-issue-156228.k3Rmxw.rst new file mode 100644 index 00000000000000..536bcd44c92111 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2026-08-22-10-30-00.gh-issue-156228.k3Rmxw.rst @@ -0,0 +1,4 @@ +The :mod:`ssl` and :mod:`hashlib` modules now route OpenSSL memory +allocations through the Python raw memory allocators, making OpenSSL memory +usage visible to :mod:`tracemalloc` and to custom allocators installed with +:c:func:`PyMem_SetAllocator`. diff --git a/Modules/_hashopenssl.c b/Modules/_hashopenssl.c index f895c9037485c4..d23767afeb96cf 100644 --- a/Modules/_hashopenssl.c +++ b/Modules/_hashopenssl.c @@ -27,6 +27,7 @@ #include "pycore_strhex.h" // _Py_strhex() #include "pycore_pyatomic_ft_wrappers.h" // FT_ATOMIC_LOAD_PTR_RELAXED #include "hashlib.h" +#include "_openssl_mem.h" /* EVP is the preferred interface to hashing in OpenSSL */ #include @@ -2933,5 +2934,6 @@ static struct PyModuleDef _hashlibmodule = { PyMODINIT_FUNC PyInit__hashlib(void) { + _PyOpenSSL_SetupMemFunctions(); return PyModuleDef_Init(&_hashlibmodule); } diff --git a/Modules/_openssl_mem.h b/Modules/_openssl_mem.h new file mode 100644 index 00000000000000..5284d9b5e63361 --- /dev/null +++ b/Modules/_openssl_mem.h @@ -0,0 +1,56 @@ +// Route OpenSSL allocations through the raw memory allocators. +// Shared by the _ssl and _hashlib modules. + +#ifndef Py_OPENSSL_MEM_H +#define Py_OPENSSL_MEM_H + +#include "Python.h" + +#include // CRYPTO_set_mem_functions() + +// LibreSSL stubs out CRYPTO_set_mem_functions() and BoringSSL lacks it. +// AWS-LC has it, but unlike OpenSSL it does not refuse to install hooks +// after the first allocation, so earlier size-prefixed allocations would +// be freed with the wrong allocator. +#if !defined(LIBRESSL_VERSION_NUMBER) && !defined(OPENSSL_IS_BORINGSSL) \ + && !defined(OPENSSL_IS_AWSLC) +# define _Py_OPENSSL_CAN_SET_MEM_FUNCTIONS +#endif + +#ifdef _Py_OPENSSL_CAN_SET_MEM_FUNCTIONS + +static void * +_PyOpenSSL_Malloc(size_t size, const char *Py_UNUSED(file), + int Py_UNUSED(line)) +{ + return PyMem_RawMalloc(size); +} + +static void * +_PyOpenSSL_Realloc(void *ptr, size_t size, const char *Py_UNUSED(file), + int Py_UNUSED(line)) +{ + return PyMem_RawRealloc(ptr, size); +} + +static void +_PyOpenSSL_Free(void *ptr, const char *Py_UNUSED(file), + int Py_UNUSED(line)) +{ + PyMem_RawFree(ptr); +} + +#endif // _Py_OPENSSL_CAN_SET_MEM_FUNCTIONS + +static void +_PyOpenSSL_SetupMemFunctions(void) +{ +#ifdef _Py_OPENSSL_CAN_SET_MEM_FUNCTIONS + // Fails if OpenSSL has already allocated memory (e.g. another + // libcrypto user in the process); it then keeps its current allocator. + (void)CRYPTO_set_mem_functions(_PyOpenSSL_Malloc, _PyOpenSSL_Realloc, + _PyOpenSSL_Free); +#endif +} + +#endif // !Py_OPENSSL_MEM_H diff --git a/Modules/_ssl.c b/Modules/_ssl.c index 9f8a6a58cd9327..fd3e03cf4bc440 100644 --- a/Modules/_ssl.c +++ b/Modules/_ssl.c @@ -41,6 +41,7 @@ #endif #include "_ssl.h" +#include "_openssl_mem.h" /* Redefined below for Windows debug builds after important #includes */ #define _PySSL_FIX_ERRNO @@ -7475,5 +7476,6 @@ static struct PyModuleDef _sslmodule_def = { PyMODINIT_FUNC PyInit__ssl(void) { + _PyOpenSSL_SetupMemFunctions(); return PyModuleDef_Init(&_sslmodule_def); } diff --git a/PCbuild/_hashlib.vcxproj b/PCbuild/_hashlib.vcxproj index 2cd205224bc089..e0110f32f201f1 100644 --- a/PCbuild/_hashlib.vcxproj +++ b/PCbuild/_hashlib.vcxproj @@ -97,6 +97,9 @@ ws2_32.lib;%(AdditionalDependencies) + + + diff --git a/PCbuild/_hashlib.vcxproj.filters b/PCbuild/_hashlib.vcxproj.filters index 7a0700c007f644..d26954116bb5ed 100644 --- a/PCbuild/_hashlib.vcxproj.filters +++ b/PCbuild/_hashlib.vcxproj.filters @@ -4,6 +4,9 @@ {cc45963d-bd25-4eb8-bdba-a5507090bca4} + + {5abcdd3e-a8bc-4833-949c-9477609092b9} + {67630fa4-76e4-4035-bced-043a6df1e2e0} @@ -13,6 +16,11 @@ Source Files + + + Header Files + + Resource Files diff --git a/PCbuild/_ssl.vcxproj b/PCbuild/_ssl.vcxproj index ce21f992ff8510..127b76fe11e329 100644 --- a/PCbuild/_ssl.vcxproj +++ b/PCbuild/_ssl.vcxproj @@ -97,6 +97,9 @@ ws2_32.lib;crypt32.lib;%(AdditionalDependencies) + + + diff --git a/PCbuild/_ssl.vcxproj.filters b/PCbuild/_ssl.vcxproj.filters index 8aef9e03fcc429..e96da0580e01b4 100644 --- a/PCbuild/_ssl.vcxproj.filters +++ b/PCbuild/_ssl.vcxproj.filters @@ -4,6 +4,9 @@ {695348f7-e9f6-4fe1-bc03-5f08ffc8095b} + + {7c1bd5da-8912-4107-b6ac-f3930f2d90c7} + {1b18a2e6-040d-46c7-a9ac-ac2ec64fb5d6} @@ -13,6 +16,11 @@ Source Files + + + Header Files + + Resource Files