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
# 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
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
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)
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
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)
curl_trc.c \
cw-out.c \
dict.c \
+ dllmain.c \
doh.c \
dynbuf.c \
dynhds.c \
--- /dev/null
+/***************************************************************************
+ * _ _ ____ _
+ * 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 */