Skip to content

Commit

Permalink
Fixed crash caused by unloading NScurl.dll after curl_global_init(..)…
Browse files Browse the repository at this point in the history
… and curl_global_cleanup(..) get called.

Once curl gets initialized NScurl.dll will be pinned in memory until the process exits.
  • Loading branch information
negrutiu committed Jun 21, 2020
1 parent a149617 commit f177e08
Show file tree
Hide file tree
Showing 4 changed files with 46 additions and 5 deletions.
38 changes: 36 additions & 2 deletions curl.c
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@


typedef struct {
volatile HMODULE hPinnedModule;
CRITICAL_SECTION csLock;
CHAR szVersion[64];
CHAR szUserAgent[128];
Expand Down Expand Up @@ -185,7 +186,6 @@ ULONG CurlInitialize()
_snprintf( g_Curl.szUserAgent, ARRAYSIZE( g_Curl.szUserAgent ), "nscurl/%s", g_Curl.szVersion );
}

curl_global_init( CURL_GLOBAL_ALL );
return ERROR_SUCCESS;
}

Expand All @@ -196,7 +196,41 @@ void CurlDestroy()
TRACE( _T( "%hs()\n" ), __FUNCTION__ );

DeleteCriticalSection( &g_Curl.csLock );
curl_global_cleanup();
}


//++ CurlInitializeLibcurl
ULONG CurlInitializeLibcurl()
{
if (InterlockedCompareExchangePointer( &g_Curl.hPinnedModule, NULL, NULL ) == NULL) {

TCHAR szPath[MAX_PATH];
TRACE( _T( "%hs()\n" ), __FUNCTION__ );

// Initialize libcurl
curl_global_init( CURL_GLOBAL_ALL );

//! CAUTION:
//? https://curl.haxx.se/libcurl/c/curl_global_cleanup.html
//? curl_global_cleanup does not block waiting for any libcurl-created threads
//? to terminate (such as threads used for name resolving). If a module 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.

// It's confirmed that NScurl.dll crashes when unloaded after curl_global_cleanup() gets called
// Easily reproducible in XP and Vista
//! We'll pin it in memory forever and never call curl_global_cleanup()
if (GetModuleFileName( g_hInst, szPath, ARRAYSIZE( szPath ) ) > 0) {
g_Curl.hPinnedModule = LoadLibrary( szPath );
assert( g_Curl.hPinnedModule );
}

// kernel32!GetModuleHandleEx is available in XP+
//x GetModuleHandleEx( GET_MODULE_HANDLE_EX_FLAG_PIN | GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS, (LPCTSTR)__FUNCTION__, (HMODULE*)&g_Curl.hPinnedModule );
}

return ERROR_SUCCESS;
}


Expand Down
3 changes: 3 additions & 0 deletions curl.h
Original file line number Diff line number Diff line change
Expand Up @@ -148,6 +148,9 @@ ULONG CurlRequestErrorCode( _In_ PCURL_REQUEST pReq ); //? e.g. 404
//+ Initialization
ULONG CurlInitialize();
void CurlDestroy();

ULONG CurlInitializeLibcurl(); //! Must be called only when starting transfers. This will lock NScurl.dll in memory until the process exists

ULONG CurlExtractCacert(); /// Called automatically

//+ CurlParseRequestParam
Expand Down
6 changes: 5 additions & 1 deletion main.c
Original file line number Diff line number Diff line change
Expand Up @@ -235,9 +235,13 @@ void __cdecl http( HWND parent, int string_size, TCHAR *variables, stack_t **sta

TRACE( _T( "%s!%hs\n" ), PLUGINNAME, __FUNCTION__ );

// Lock the plugin in memory
// Lock the plugin in memory (against NSIS framework trying to unload it)
extra->RegisterPluginCallback( g_hInst, UnloadCallback );

// Lock the plugin in memory (against Windows itself trying to FreeLibrary it)
// Once curl_global_init gets called, the current module must never unload
CurlInitializeLibcurl();

// Working structures
psz = (LPTSTR)MyAlloc( string_size * sizeof(TCHAR) );
pReq = (PCURL_REQUEST)MyAlloc( sizeof( *pReq ) );
Expand Down
4 changes: 2 additions & 2 deletions resource.rc
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ END
//

VS_VERSION_INFO VERSIONINFO
FILEVERSION 1,2020,6,6
FILEVERSION 1,2020,6,21
PRODUCTVERSION 1,0,0,0
FILEFLAGSMASK 0x3fL
#ifdef _DEBUG
Expand All @@ -69,7 +69,7 @@ BEGIN
BEGIN
VALUE "CompanyName", "Marius Negrutiu ([email protected])"
VALUE "FileDescription", "NSIS libcurl plugin"
VALUE "FileVersion", "1.2020.6.6"
VALUE "FileVersion", "1.2020.6.21"
VALUE "InternalName", "NScurl.dll"
VALUE "LegalCopyright", "(C)2019-present, Marius Negrutiu. All rights reserved."
VALUE "LegalTrademarks", "https://github.com/negrutiu/nsis-nscurl"
Expand Down

0 comments on commit f177e08

Please sign in to comment.