New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
dllmain: Call OpenSSL thread cleanup for Windows and Cygwin #12408
Conversation
This is on hold because we're still investigating #12327 |
b79f675
to
3b2522f
Compare
@vszakats can you take a look at the unity logic please. In dllmain.c I needed to include windows.h for cygwin but I don't want that being included by other units (like if they were combined in a unity build) so I added some logic to exempt it in cmake, but I'm not sure if anything else is needed for other build systems. |
@jay: |
|
CURL_STATICLIB is meant to be defined for static libcurl only. I do not think it should be defined for libcurl DLL. Lines 112 to 118 in d755a5f
That seems like a hack. How about if we introduce another symbol to handle that situation, for example diff --git a/include/curl/curl.h b/include/curl/curl.h
index 94d9053..7028890 100644
--- a/include/curl/curl.h
+++ b/include/curl/curl.h
@@ -117,7 +117,7 @@ typedef void CURLSH;
* libcurl external API function linkage decorations.
*/
-#ifdef CURL_STATICLIB
+#if defined(CURL_STATICLIB) || defined(CURL_DISALLOW_EXTERN)
# define CURL_EXTERN
#elif defined(_WIN32) || \
(__has_declspec_attribute(dllexport) && \ |
IMO Using At this point I wouldn't touch this in I think a better approach for CMake would be to limit compiling --- a/lib/CMakeLists.txt
+++ b/lib/CMakeLists.txt
@@ -182,7 +182,7 @@ if(BUILD_SHARED_LIBS)
add_library(${LIB_SHARED} SHARED ${LIB_SOURCE})
add_library(${PROJECT_NAME}::${LIB_SHARED} ALIAS ${LIB_SHARED})
if(WIN32)
- set_property(TARGET ${LIB_SHARED} APPEND PROPERTY SOURCES libcurl.rc)
+ set_property(TARGET ${LIB_SHARED} APPEND PROPERTY SOURCES dllmain.c libcurl.rc)
if(HIDES_CURL_PRIVATE_SYMBOLS)
set_property(TARGET ${LIB_SHARED} APPEND PROPERTY SOURCES "${CURL_SOURCE_DIR}/libcurl.def")
endif() The next problem is how to enable it inside CMake patch for the above: --- a/lib/CMakeLists.txt
+++ b/lib/CMakeLists.txt
@@ -181,8 +181,10 @@ 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})
+ unset(_shared_compile_definitions)
if(WIN32)
- set_property(TARGET ${LIB_SHARED} APPEND PROPERTY SOURCES libcurl.rc)
+ set_property(TARGET ${LIB_SHARED} APPEND PROPERTY SOURCES libcurl.rc dllmain.c)
+ list(APPEND _shared_compile_definitions "DLL_EXPORT")
if(HIDES_CURL_PRIVATE_SYMBOLS)
set_property(TARGET ${LIB_SHARED} APPEND PROPERTY SOURCES "${CURL_SOURCE_DIR}/libcurl.def")
endif()
@@ -195,7 +197,10 @@ if(BUILD_SHARED_LIBS)
POSITION_INDEPENDENT_CODE ON)
if(HIDES_CURL_PRIVATE_SYMBOLS)
set_property(TARGET ${LIB_SHARED} APPEND PROPERTY COMPILE_FLAGS "${CURL_CFLAG_SYMBOLS_HIDE}")
- set_property(TARGET ${LIB_SHARED} APPEND PROPERTY COMPILE_DEFINITIONS "CURL_HIDDEN_SYMBOLS")
+ list(APPEND _shared_compile_definitions "CURL_HIDDEN_SYMBOLS")
+ endif()
+ if(_shared_compile_definitions)
+ set_property(TARGET ${LIB_SHARED} APPEND PROPERTY COMPILE_DEFINITIONS ${_shared_compile_definitions})
endif()
if(CURL_HAS_LTO)
set_target_properties(${LIB_SHARED} PROPERTIES |
Here's a rough patch building seemingly fine with CMake (while also keeping autotools working, but not tested). Except this:
diff --git a/lib/CMakeLists.txt b/lib/CMakeLists.txt
index 51d52578e..2e99c7861 100644
--- a/lib/CMakeLists.txt
+++ b/lib/CMakeLists.txt
@@ -181,10 +181,17 @@ 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})
+ unset(_shared_compile_sources)
+ unset(_shared_compile_definitions)
+ if(WIN32 OR CYGWIN)
+ set_source_files_properties(${LIB_DLLMAIN} PROPERTIES SKIP_UNITY_BUILD_INCLUSION ON)
+ list(APPEND _shared_compile_sources ${LIB_DLLMAIN})
+ list(APPEND _shared_compile_definitions "DLL_EXPORT")
+ endif()
if(WIN32)
- set_property(TARGET ${LIB_SHARED} APPEND PROPERTY SOURCES libcurl.rc)
+ list(APPEND _shared_compile_sources ${LIB_RCFILES})
if(HIDES_CURL_PRIVATE_SYMBOLS)
- set_property(TARGET ${LIB_SHARED} APPEND PROPERTY SOURCES "${CURL_SOURCE_DIR}/libcurl.def")
+ list(APPEND _shared_compile_sources "${CURL_SOURCE_DIR}/libcurl.def")
endif()
endif()
target_link_libraries(${LIB_SHARED} PRIVATE ${CURL_LIBS})
@@ -195,7 +202,13 @@ if(BUILD_SHARED_LIBS)
POSITION_INDEPENDENT_CODE ON)
if(HIDES_CURL_PRIVATE_SYMBOLS)
set_property(TARGET ${LIB_SHARED} APPEND PROPERTY COMPILE_FLAGS "${CURL_CFLAG_SYMBOLS_HIDE}")
- set_property(TARGET ${LIB_SHARED} APPEND PROPERTY COMPILE_DEFINITIONS "CURL_HIDDEN_SYMBOLS")
+ list(APPEND _shared_compile_definitions "CURL_HIDDEN_SYMBOLS")
+ endif()
+ if(_shared_compile_sources)
+ set_property(TARGET ${LIB_SHARED} APPEND PROPERTY SOURCES ${_shared_compile_sources})
+ endif()
+ if(_shared_compile_definitions)
+ set_property(TARGET ${LIB_SHARED} APPEND PROPERTY COMPILE_DEFINITIONS ${_shared_compile_definitions})
endif()
if(CURL_HAS_LTO)
set_target_properties(${LIB_SHARED} PROPERTIES
diff --git a/lib/Makefile.am b/lib/Makefile.am
index 1237c8e99..5ce7c5650 100644
--- a/lib/Makefile.am
+++ b/lib/Makefile.am
@@ -70,6 +70,8 @@ include Makefile.inc
libcurl_la_SOURCES = $(CSOURCES) $(HHEADERS)
libcurlu_la_SOURCES = $(CSOURCES) $(HHEADERS)
+libcurl_la_SOURCES += $(LIB_DLLMAIN)
+
libcurl_la_CPPFLAGS_EXTRA =
libcurl_la_LDFLAGS_EXTRA =
libcurl_la_CFLAGS_EXTRA =
diff --git a/lib/Makefile.inc b/lib/Makefile.inc
index e568ef953..46af66273 100644
--- a/lib/Makefile.inc
+++ b/lib/Makefile.inc
@@ -362,6 +362,8 @@ LIB_HFILES = \
warnless.h \
ws.h
+LIB_DLLMAIN = dllmain.c
+
LIB_RCFILES = libcurl.rc
CSOURCES = $(LIB_CFILES) $(LIB_VAUTH_CFILES) $(LIB_VTLS_CFILES) \
--- a/lib/dllmain.c
+++ b/lib/dllmain.c
@@ -24,17 +24,15 @@
#include "curl_setup.h"
-#if (defined(_WIN32) || defined(__CYGWIN__)) && !defined(CURL_STATICLIB)
+#if (defined(_WIN32) || defined(__CYGWIN__)) && defined(DLL_EXPORT)
/* 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 <windows.h>
-#endif
#ifdef USE_OPENSSL
#include <openssl/crypto.h>
@@ -64,4 +62,4 @@
return TRUE;
}
-#endif /* (_WIN32 || __CYGWIN__) && !CURL_STATICLIB */
+#endif /* (_WIN32 || __CYGWIN__) && DLL_EXPORT */ |
It's great that it's possible to do a single pass with CMake for both shared and static but we have to account for other build systems. Also we tell the user to define CURL_STATICLIB if libcurl is linked statically.
Alright let's say we leave it win32 CURL_STATICLIB always for cmake. I'm sure there is a way to still allow cmake to do a single pass while allowing the other build systems to do their thing.
Couldn't this be addressed by leaving dllmain check as I did it (ie check for !CURL_STATICLIB) but then also telling cmake not to |
That's what my patch tries to do. Except for native MSVC builds which I'm
Maybe it can be done, but I find that more confusing than the proposal above. |
Official (Can't add much to this though, I'm lost when OpenSSL requires this deinit call.) |
Here's one take reusing Notably it drops (works with the unmodified diff --git a/lib/CMakeLists.txt b/lib/CMakeLists.txt
index 51d52578e..e0ce3eacd 100644
--- a/lib/CMakeLists.txt
+++ b/lib/CMakeLists.txt
@@ -114,23 +114,26 @@ 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})
+ unset(_object_compile_definitions)
+ 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.
+ list(APPEND _object_compile_definitions "CURL_STATICLIB")
+ endif()
target_link_libraries(${LIB_OBJECT} PRIVATE ${CURL_LIBS})
set_target_properties(${LIB_OBJECT} PROPERTIES
POSITION_INDEPENDENT_CODE ON)
if(HIDES_CURL_PRIVATE_SYMBOLS)
set_property(TARGET ${LIB_OBJECT} APPEND PROPERTY COMPILE_FLAGS "${CURL_CFLAG_SYMBOLS_HIDE}")
- set_property(TARGET ${LIB_OBJECT} APPEND PROPERTY COMPILE_DEFINITIONS "CURL_HIDDEN_SYMBOLS")
+ list(APPEND _object_compile_definitions "CURL_HIDDEN_SYMBOLS")
+ endif()
+ if(_object_compile_definitions)
+ set_property(TARGET ${LIB_OBJECT} APPEND PROPERTY COMPILE_DEFINITIONS ${_object_compile_definitions})
endif()
if(CURL_HAS_LTO)
set_target_properties(${LIB_OBJECT} PROPERTIES
@@ -152,6 +155,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})
+ unset(_static_compile_definitions)
+ if(WIN32)
+ list(APPEND _static_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
@@ -160,7 +167,10 @@ if(BUILD_STATIC_LIBS)
INTERFACE_COMPILE_DEFINITIONS "CURL_STATICLIB")
if(HIDES_CURL_PRIVATE_SYMBOLS)
set_property(TARGET ${LIB_STATIC} APPEND PROPERTY COMPILE_FLAGS "${CURL_CFLAG_SYMBOLS_HIDE}")
- set_property(TARGET ${LIB_STATIC} APPEND PROPERTY COMPILE_DEFINITIONS "CURL_HIDDEN_SYMBOLS")
+ list(APPEND _static_compile_definitions "CURL_HIDDEN_SYMBOLS")
+ endif()
+ if(_static_compile_definitions)
+ set_property(TARGET ${LIB_STATIC} APPEND PROPERTY COMPILE_DEFINITIONS ${_static_compile_definitions})
endif()
if(CURL_HAS_LTO)
set_target_properties(${LIB_STATIC} PROPERTIES
@@ -181,10 +191,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})
+ unset(_shared_compile_sources)
+ if(WIN32 OR CYGWIN)
+ set_source_files_properties(${LIB_DLLMAIN} PROPERTIES SKIP_UNITY_BUILD_INCLUSION ON)
+ list(APPEND _shared_compile_sources ${LIB_DLLMAIN})
+ endif()
if(WIN32)
- set_property(TARGET ${LIB_SHARED} APPEND PROPERTY SOURCES libcurl.rc)
+ list(APPEND _shared_compile_sources ${LIB_RCFILES})
if(HIDES_CURL_PRIVATE_SYMBOLS)
- set_property(TARGET ${LIB_SHARED} APPEND PROPERTY SOURCES "${CURL_SOURCE_DIR}/libcurl.def")
+ list(APPEND _shared_compile_sources "${CURL_SOURCE_DIR}/libcurl.def")
endif()
endif()
target_link_libraries(${LIB_SHARED} PRIVATE ${CURL_LIBS})
@@ -197,6 +212,9 @@ if(BUILD_SHARED_LIBS)
set_property(TARGET ${LIB_SHARED} APPEND PROPERTY COMPILE_FLAGS "${CURL_CFLAG_SYMBOLS_HIDE}")
set_property(TARGET ${LIB_SHARED} APPEND PROPERTY COMPILE_DEFINITIONS "CURL_HIDDEN_SYMBOLS")
endif()
+ if(_shared_compile_sources)
+ set_property(TARGET ${LIB_SHARED} APPEND PROPERTY SOURCES ${_shared_compile_sources})
+ endif()
if(CURL_HAS_LTO)
set_target_properties(${LIB_SHARED} PROPERTIES
INTERPROCEDURAL_OPTIMIZATION_RELEASE TRUE |
|
@vszakats I made some changes: dllmain.c is now added only to CMake Windows and Cygwin SHARED (DLL) builds and built with CURL_CMAKE_DLLMAIN. When both shared and static libs are built by CMake it will still do a single pass. OPENSSL_thread_stop() is now not called for LibreSSL, BoringSSL, AWS-LC. Is I temporarily added a MessageBox on THREAD_DETACH for debugging purposes. |
I tested it and it revealed two things:
This lead to this patch (over the current PR), which stops setting diff --git a/lib/CMakeLists.txt b/lib/CMakeLists.txt
index 39b744d89..8e95f0477 100644
--- a/lib/CMakeLists.txt
+++ b/lib/CMakeLists.txt
@@ -33,8 +33,6 @@ include(${CMAKE_CURRENT_BINARY_DIR}/Makefile.inc.cmake)
# DllMain is added later for DLL builds only.
list(REMOVE_ITEM CSOURCES dllmain.c)
-set_source_files_properties(dllmain.c PROPERTIES
- COMPILE_FLAGS -DCURL_CMAKE_DLLMAIN)
list(APPEND HHEADERS ${CMAKE_CURRENT_BINARY_DIR}/curl_config.h)
@@ -66,13 +64,6 @@ if(ENABLE_CURLDEBUG)
set_source_files_properties(memdebug.c curl_multibyte.c PROPERTIES SKIP_UNITY_BUILD_INCLUSION ON)
endif()
-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()
-
if(BUILD_TESTING)
target_link_libraries(curlu PRIVATE ${CURL_LIBS})
endif()
@@ -124,17 +115,16 @@ 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)
@@ -162,6 +152,9 @@ 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
@@ -192,6 +185,11 @@ if(BUILD_SHARED_LIBS)
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)
diff --git a/lib/dllmain.c b/lib/dllmain.c
index 6d9753e43..5f5a241a5 100644
--- a/lib/dllmain.c
+++ b/lib/dllmain.c
@@ -44,14 +44,10 @@
/*
* DllMain() must only be defined for Windows and Cygwin DLL builds. For most
- * build systems that means CURL_STATICLIB is not defined. However, CMake
- * defines CURL_STATICLIB always for Windows builds (discussion in #12408).
- * CMake builds dllmain.c only for Windows and Cygwin DLL builds and defines
- * CURL_CMAKE_DLLMAIN.
+ * build systems that means CURL_STATICLIB is not defined.
*/
-#if (defined(_WIN32) || defined(__CYGWIN__)) && \
- (!defined(CURL_STATICLIB) || defined(CURL_CMAKE_DLLMAIN))
+#if (defined(_WIN32) || defined(__CYGWIN__)) && !defined(CURL_STATICLIB)
BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved); |
Some of these word checks are snobby. It doesn't like the word |
- 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: [email protected] Reported-by: [email protected] Ref: https://www.openssl.org/docs/man3.0/man3/OPENSSL_thread_stop.html#NOTES Fixes curl#12327 Closes #xxxx
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 in some cases OpenSSL may need a call to OPENSSL_thread_stop before thread termination in order to stop a memory leak.
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.
Reported-by: [email protected]
Reported-by: [email protected]
Ref: https://www.openssl.org/docs/man3.0/man3/OPENSSL_thread_stop.html#NOTES
Fixes #12327
Closes #xxxx