aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPavel P <pavlov.pavel@gmail.com>2024-05-02 06:15:44 +0200
committerJay Satiro <raysatiro@yahoo.com>2024-05-07 14:54:11 -0400
commit428579f5d136fd473e97fe089c42ffee55b72a8f (patch)
tree0e40b48ae58df1729bae2f17162bee040f4cb8b3
parent62ae1f10e59423e7924a615c79a08dca081cf6ab (diff)
downloadcurl-428579f5d136fd473e97fe089c42ffee55b72a8f.tar.gz
asyn-thread: fix curl_global_cleanup crash in Windows
- Make sure that asynchronous resolves handled by Winsock are stopped before WSACleanup is called. This is implemented by ensuring that when Curl_resolver_kill is called (eg via multi_done) it will cancel the Winsock asynchronous resolve and wait for the cancellation to complete. Winsock runs the asynchronous completion routine immediately when a resolve is canceled. Prior to this change it was possible that during curl_global_cleanup "a DNS resolver thread created by GetAddrInfoExW did not terminate yet, however curl is already shutting down, deinitializing Winsock with WSACleanup() leading to an access violation." Background: If libcurl is built with the asynchronous threaded resolver option for Windows then it resolves in one of two ways. For Windows 8.1 and later, libcurl resolves by using the Winsock asynchronous resolver which does its own thread management. For older versions of Windows, libcurl resolves by creating a separate thread that calls getaddrinfo. This change only affects the former and it's already handled for the latter. Reported-by: Ch40zz@users.noreply.github.com Fixes https://github.com/curl/curl/issues/13509 Closes https://github.com/curl/curl/pull/13518
-rw-r--r--lib/asyn-thread.c19
-rw-r--r--lib/curl_threads.c3
2 files changed, 18 insertions, 4 deletions
diff --git a/lib/asyn-thread.c b/lib/asyn-thread.c
index f537c0b9f..1760d6cb3 100644
--- a/lib/asyn-thread.c
+++ b/lib/asyn-thread.c
@@ -554,11 +554,15 @@ static void destroy_async_data(struct Curl_async *async)
if(!done) {
#ifdef _WIN32
- if(td->complete_ev)
+ if(td->complete_ev) {
CloseHandle(td->complete_ev);
- else
+ td->complete_ev = NULL;
+ }
#endif
- Curl_thread_destroy(td->thread_hnd);
+ if(td->thread_hnd != curl_thread_t_null) {
+ Curl_thread_destroy(td->thread_hnd);
+ td->thread_hnd = curl_thread_t_null;
+ }
}
else {
#ifdef _WIN32
@@ -566,6 +570,7 @@ static void destroy_async_data(struct Curl_async *async)
Curl_GetAddrInfoExCancel(&td->tsd.w8.cancel_ev);
WaitForSingleObject(td->complete_ev, INFINITE);
CloseHandle(td->complete_ev);
+ td->complete_ev = NULL;
}
#endif
if(td->thread_hnd != curl_thread_t_null)
@@ -713,6 +718,7 @@ static CURLcode thread_wait_resolv(struct Curl_easy *data,
if(td->complete_ev) {
WaitForSingleObject(td->complete_ev, INFINITE);
CloseHandle(td->complete_ev);
+ td->complete_ev = NULL;
if(entry)
result = getaddrinfo_complete(data);
}
@@ -754,6 +760,13 @@ void Curl_resolver_kill(struct Curl_easy *data)
/* If we're still resolving, we must wait for the threads to fully clean up,
unfortunately. Otherwise, we can simply cancel to clean up any resolver
data. */
+#ifdef _WIN32
+ if(td && td->complete_ev) {
+ Curl_GetAddrInfoExCancel(&td->tsd.w8.cancel_ev);
+ (void)thread_wait_resolv(data, NULL, FALSE);
+ }
+ else
+#endif
if(td && td->thread_hnd != curl_thread_t_null
&& (data->set.quick_exit != 1L))
(void)thread_wait_resolv(data, NULL, FALSE);
diff --git a/lib/curl_threads.c b/lib/curl_threads.c
index 222d9364f..93fa2dafb 100644
--- a/lib/curl_threads.c
+++ b/lib/curl_threads.c
@@ -131,7 +131,8 @@ curl_thread_t Curl_thread_create(unsigned int (CURL_STDCALL *func) (void *),
void Curl_thread_destroy(curl_thread_t hnd)
{
- CloseHandle(hnd);
+ if(hnd != curl_thread_t_null)
+ CloseHandle(hnd);
}
int Curl_thread_join(curl_thread_t *hnd)