diff --git a/docs/libcurl/curl_global_cleanup.3 b/docs/libcurl/curl_global_cleanup.3 index b409494111b440..d56a195a96dd7e 100644 --- a/docs/libcurl/curl_global_cleanup.3 +++ b/docs/libcurl/curl_global_cleanup.3 @@ -56,6 +56,9 @@ containing libcurl is dynamically unloaded while libcurl-created threads are 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. + +OpenSSL may require thread cleanup in some unusual cases so that it won't leak +memory. Refer to \fIlibcurl-thread(3)\fP. .SH EXAMPLE .nf curl_global_init(CURL_GLOBAL_DEFAULT); diff --git a/docs/libcurl/libcurl-thread.3 b/docs/libcurl/libcurl-thread.3 index 397eeae6687c8f..a7a146febffcb6 100644 --- a/docs/libcurl/libcurl-thread.3 +++ b/docs/libcurl/libcurl-thread.3 @@ -42,10 +42,22 @@ interface but you must provide your own locking and set Note that some items are specifically documented as not thread-safe in the share API (the connection pool and HSTS cache for example). .SH 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 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. + +OpenSSL may require thread cleanup in some unusual cases so that it won't leak +memory. The most significant case of this is if OpenSSL was linked statically. +For example, in Windows if both libcurl and OpenSSL are linked statically to a +DLL or application then OpenSSL will leak memory unless the DLL or application +calls OPENSSL_thread_stop() before each thread terminates. However, if libcurl +is built as a DLL and OpenSSL is linked statically to it then since libcurl +8.5.0 it will call OPENSSL_thread_stop() for you. Otherwise, libcurl cannot +call it for you and it is up to the DLL or application. There are several other +cases that are unusual. Refer to OpenSSL documentation: +https://www.openssl.org/docs/man3.0/man3/OPENSSL_thread_stop.html#NOTES .SH "Signals" Signals are used for timing out name resolves (during DNS lookup) - when built without using either the c-ares or threaded resolver backends. On systems that diff --git a/lib/CMakeLists.txt b/lib/CMakeLists.txt index 51d52578ed209f..982ed179f97768 100644 --- a/lib/CMakeLists.txt +++ b/lib/CMakeLists.txt @@ -63,6 +63,12 @@ if(ENABLE_CURLDEBUG) set_source_files_properties(memdebug.c curl_multibyte.c PROPERTIES SKIP_UNITY_BUILD_INCLUSION ON) endif() +if(CYGWIN) + # for cygwin compile dllmain.c separately since it includes windows.h, which + # shouldn't be included for other units. + set_source_files_properties(dllmain.c PROPERTIES SKIP_UNITY_BUILD_INCLUSION ON) +endif() + if(BUILD_TESTING) target_link_libraries(curlu PRIVATE ${CURL_LIBS}) endif() diff --git a/lib/Makefile.inc b/lib/Makefile.inc index e568ef95353399..dfc5c2c01fe0fd 100644 --- a/lib/Makefile.inc +++ b/lib/Makefile.inc @@ -134,6 +134,7 @@ LIB_CFILES = \ curl_threads.c \ curl_trc.c \ dict.c \ + dllmain.c \ doh.c \ dynbuf.c \ dynhds.c \ diff --git a/lib/dllmain.c b/lib/dllmain.c new file mode 100644 index 00000000000000..48d79f734741ec --- /dev/null +++ b/lib/dllmain.c @@ -0,0 +1,67 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , 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" + +#if (defined(_WIN32) || defined(__CYGWIN__)) && !defined(CURL_STATICLIB) + +/* WARNING: Including Cygwin windows.h may define _WIN32 in old versions or + may have unexpected behavior in unity builds (where all source files are + bundled into a single unit). For that reason, this source file must be + compiled separately for Cygwin unity builds. */ + +#ifdef __CYGWIN__ +#define WIN32_LEAN_AND_MEAN +#include +#endif + +#ifdef USE_OPENSSL +#include +#endif + +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: +#if defined(USE_OPENSSL) && (OPENSSL_VERSION_NUMBER >= 0x10100000L) + /* 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(); +#endif + break; + } + return TRUE; +} + +#endif /* (_WIN32 || __CYGWIN__) && !CURL_STATICLIB */