dllmain: Call OpenSSL thread cleanup for Windows and Cygwin
- Call OPENSSL_thread_stop on thread termination (DLL_THREAD_DETACH) to prevent a memory leak in case OpenSSL is linked statically. - Warn in libcurl-thread.3 that if OpenSSL is linked statically then it may require thread cleanup. OpenSSL may need per-thread cleanup to stop a memory leak. For Windows and Cygwin if libcurl was built as a DLL then we can do that for the user by calling OPENSSL_thread_stop on thread termination. However, if libcurl was built statically then we do not have notification of thread termination and cannot do that for the user. Also, there are several other unusual cases where it may be necessary for the user to call OPENSSL_thread_stop, so in the libcurl-thread warning I added a link to the OpenSSL documentation. Co-authored-by: Viktor Szakats Reported-by: southernedge@users.noreply.github.com Reported-by: zmcx16@users.noreply.github.com Ref: https://www.openssl.org/docs/man3.0/man3/OPENSSL_thread_stop.html#NOTES Fixes https://github.com/curl/curl/issues/12327 Closes https://github.com/curl/curl/pull/12408
This commit is contained in:
Родитель
3b8db84c1b
Коммит
7860f575fe
|
@ -54,6 +54,11 @@ still running then your program may crash or other corruption may occur. We
|
|||
recommend you do not run libcurl from any module that may be unloaded
|
||||
dynamically. This behavior may be addressed in the future.
|
||||
|
||||
libcurl may not be able to fully clean up after multi-threaded OpenSSL
|
||||
depending on how OpenSSL was built and loaded as a library. It is possible in
|
||||
some rare circumstances a memory leak could occur unless you implement your own
|
||||
OpenSSL thread cleanup. Refer to libcurl-thread(3).
|
||||
|
||||
# EXAMPLE
|
||||
|
||||
~~~c
|
||||
|
|
|
@ -37,10 +37,28 @@ share API (the connection pool and HSTS cache for example).
|
|||
|
||||
# TLS
|
||||
|
||||
All current TLS libraries libcurl supports are thread-safe. OpenSSL 1.1.0+ can
|
||||
be safely used in multi-threaded applications provided that support for the
|
||||
underlying OS threading API is built-in. For older versions of OpenSSL, the
|
||||
user must set mutex callbacks.
|
||||
All current TLS libraries libcurl supports are thread-safe.
|
||||
|
||||
## OpenSSL
|
||||
|
||||
OpenSSL 1.1.0+ can be safely used in multi-threaded applications provided that
|
||||
support for the underlying OS threading API is built-in. For older versions of
|
||||
OpenSSL, the user must set mutex callbacks.
|
||||
|
||||
libcurl may not be able to fully clean up after multi-threaded OpenSSL
|
||||
depending on how OpenSSL was built and loaded as a library. It is possible in
|
||||
some rare circumstances a memory leak could occur unless you implement your own
|
||||
OpenSSL thread cleanup.
|
||||
|
||||
For example, on Windows if both libcurl and OpenSSL are linked statically to a
|
||||
DLL or application then OpenSSL may leak memory unless the DLL or application
|
||||
calls OPENSSL_thread_stop() before each thread terminates. If OpenSSL is built
|
||||
as a DLL then it does this cleanup automatically and there is no leak. If
|
||||
libcurl is built as a DLL and OpenSSL is linked statically to it then libcurl
|
||||
does this cleanup automatically and there is no leak (added in libcurl 8.8.0).
|
||||
|
||||
Please review the OpenSSL documentation for a full list of circumstances:
|
||||
https://www.openssl.org/docs/man3.0/man3/OPENSSL_thread_stop.html#NOTES
|
||||
|
||||
# Signals
|
||||
|
||||
|
|
|
@ -31,9 +31,10 @@ configure_file(curl_config.h.cmake
|
|||
transform_makefile_inc("Makefile.inc" "${CMAKE_CURRENT_BINARY_DIR}/Makefile.inc.cmake")
|
||||
include(${CMAKE_CURRENT_BINARY_DIR}/Makefile.inc.cmake)
|
||||
|
||||
list(APPEND HHEADERS
|
||||
${CMAKE_CURRENT_BINARY_DIR}/curl_config.h
|
||||
)
|
||||
# DllMain is added later for DLL builds only.
|
||||
list(REMOVE_ITEM CSOURCES dllmain.c)
|
||||
|
||||
list(APPEND HHEADERS ${CMAKE_CURRENT_BINARY_DIR}/curl_config.h)
|
||||
|
||||
# The rest of the build
|
||||
|
||||
|
@ -114,17 +115,17 @@ if(NOT DEFINED SHARE_LIB_OBJECT)
|
|||
endif()
|
||||
endif()
|
||||
|
||||
if(WIN32)
|
||||
# Define CURL_STATICLIB always, to disable __declspec(dllexport) for exported
|
||||
# libcurl symbols. We handle exports via libcurl.def instead. Except with
|
||||
# symbol hiding disabled or debug mode enabled, when we export _all_ symbols
|
||||
# from libcurl DLL, without using libcurl.def.
|
||||
add_definitions("-DCURL_STATICLIB")
|
||||
endif()
|
||||
|
||||
if(SHARE_LIB_OBJECT)
|
||||
set(LIB_OBJECT "libcurl_object")
|
||||
add_library(${LIB_OBJECT} OBJECT ${HHEADERS} ${CSOURCES})
|
||||
if(WIN32)
|
||||
# Define CURL_STATICLIB always, to disable __declspec(dllexport) for
|
||||
# exported libcurl symbols. We handle exports via libcurl.def instead.
|
||||
# Except with symbol hiding disabled or debug mode enabled, when we export
|
||||
# _all_ symbols from libcurl DLL, without using libcurl.def.
|
||||
set_property(TARGET ${LIB_OBJECT} APPEND
|
||||
PROPERTY COMPILE_DEFINITIONS "CURL_STATICLIB")
|
||||
endif()
|
||||
target_link_libraries(${LIB_OBJECT} PRIVATE ${CURL_LIBS})
|
||||
set_target_properties(${LIB_OBJECT} PROPERTIES
|
||||
POSITION_INDEPENDENT_CODE ON)
|
||||
|
@ -152,6 +153,10 @@ if(BUILD_STATIC_LIBS)
|
|||
list(APPEND libcurl_export ${LIB_STATIC})
|
||||
add_library(${LIB_STATIC} STATIC ${LIB_SOURCE})
|
||||
add_library(${PROJECT_NAME}::${LIB_STATIC} ALIAS ${LIB_STATIC})
|
||||
if(WIN32)
|
||||
set_property(TARGET ${LIB_OBJECT} APPEND
|
||||
PROPERTY COMPILE_DEFINITIONS "CURL_STATICLIB")
|
||||
endif()
|
||||
target_link_libraries(${LIB_STATIC} PRIVATE ${CURL_LIBS})
|
||||
# Remove the "lib" prefix since the library is already named "libcurl".
|
||||
set_target_properties(${LIB_STATIC} PROPERTIES
|
||||
|
@ -181,6 +186,15 @@ if(BUILD_SHARED_LIBS)
|
|||
list(APPEND libcurl_export ${LIB_SHARED})
|
||||
add_library(${LIB_SHARED} SHARED ${LIB_SOURCE})
|
||||
add_library(${PROJECT_NAME}::${LIB_SHARED} ALIAS ${LIB_SHARED})
|
||||
if(WIN32 OR CYGWIN)
|
||||
if(CYGWIN)
|
||||
# For cygwin always compile dllmain.c as a separate unit since it
|
||||
# includes windows.h, which shouldn't be included in other units.
|
||||
set_source_files_properties(dllmain.c PROPERTIES
|
||||
SKIP_UNITY_BUILD_INCLUSION ON)
|
||||
endif()
|
||||
set_property(TARGET ${LIB_SHARED} APPEND PROPERTY SOURCES dllmain.c)
|
||||
endif()
|
||||
if(WIN32)
|
||||
set_property(TARGET ${LIB_SHARED} APPEND PROPERTY SOURCES libcurl.rc)
|
||||
if(HIDES_CURL_PRIVATE_SYMBOLS)
|
||||
|
|
|
@ -139,6 +139,7 @@ LIB_CFILES = \
|
|||
curl_trc.c \
|
||||
cw-out.c \
|
||||
dict.c \
|
||||
dllmain.c \
|
||||
doh.c \
|
||||
dynbuf.c \
|
||||
dynhds.c \
|
||||
|
|
|
@ -0,0 +1,81 @@
|
|||
/***************************************************************************
|
||||
* _ _ ____ _
|
||||
* Project ___| | | | _ \| |
|
||||
* / __| | | | |_) | |
|
||||
* | (__| |_| | _ <| |___
|
||||
* \___|\___/|_| \_\_____|
|
||||
*
|
||||
* Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
|
||||
*
|
||||
* This software is licensed as described in the file COPYING, which
|
||||
* you should have received as part of this distribution. The terms
|
||||
* are also available at https://curl.se/docs/copyright.html.
|
||||
*
|
||||
* You may opt to use, copy, modify, merge, publish, distribute and/or sell
|
||||
* copies of the Software, and permit persons to whom the Software is
|
||||
* furnished to do so, under the terms of the COPYING file.
|
||||
*
|
||||
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
|
||||
* KIND, either express or implied.
|
||||
*
|
||||
* SPDX-License-Identifier: curl
|
||||
*
|
||||
***************************************************************************/
|
||||
|
||||
#include "curl_setup.h"
|
||||
|
||||
#ifdef USE_OPENSSL
|
||||
#include <openssl/crypto.h>
|
||||
#endif
|
||||
|
||||
/* The fourth-to-last include */
|
||||
#ifdef __CYGWIN__
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#include <windows.h>
|
||||
#ifdef _WIN32
|
||||
#undef _WIN32
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/* The last 3 #include files should be in this order */
|
||||
#include "curl_printf.h"
|
||||
#include "curl_memory.h"
|
||||
#include "memdebug.h"
|
||||
|
||||
/* DllMain() must only be defined for Windows and Cygwin DLL builds. */
|
||||
#if (defined(_WIN32) || defined(__CYGWIN__)) && !defined(CURL_STATICLIB)
|
||||
|
||||
#if defined(USE_OPENSSL) && \
|
||||
!defined(OPENSSL_IS_AWSLC) && \
|
||||
!defined(OPENSSL_IS_BORINGSSL) && \
|
||||
!defined(LIBRESSL_VERSION_NUMBER) && \
|
||||
(OPENSSL_VERSION_NUMBER >= 0x10100000L)
|
||||
#define PREVENT_OPENSSL_MEMLEAK
|
||||
#endif
|
||||
|
||||
#ifdef PREVENT_OPENSSL_MEMLEAK
|
||||
BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved);
|
||||
BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
|
||||
{
|
||||
(void)hinstDLL;
|
||||
(void)lpvReserved;
|
||||
|
||||
switch(fdwReason) {
|
||||
case DLL_PROCESS_ATTACH:
|
||||
break;
|
||||
case DLL_PROCESS_DETACH:
|
||||
break;
|
||||
case DLL_THREAD_ATTACH:
|
||||
break;
|
||||
case DLL_THREAD_DETACH:
|
||||
/* Call OPENSSL_thread_stop to prevent a memory leak in case OpenSSL is
|
||||
linked statically.
|
||||
https://github.com/curl/curl/issues/12327#issuecomment-1826405944 */
|
||||
OPENSSL_thread_stop();
|
||||
break;
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
#endif /* OpenSSL */
|
||||
|
||||
#endif /* DLL build */
|
Загрузка…
Ссылка в новой задаче