diff --git a/httplib.h b/httplib.h index bb2417e6..68daf553 100644 --- a/httplib.h +++ b/httplib.h @@ -5905,58 +5905,17 @@ inline int getaddrinfo_with_timeout(const char *node, const char *service, *res = result_addrinfo; return 0; -#elif defined(_GNU_SOURCE) && defined(__GLIBC__) && \ - (__GLIBC__ > 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ >= 2)) - // Linux implementation using getaddrinfo_a for asynchronous DNS resolution - struct gaicb request; - struct gaicb *requests[1] = {&request}; - struct sigevent sevp; - struct timespec timeout; - - // Initialize the request structure - memset(&request, 0, sizeof(request)); - request.ar_name = node; - request.ar_service = service; - request.ar_request = hints; - - // Set up timeout - timeout.tv_sec = timeout_sec; - timeout.tv_nsec = 0; - - // Initialize sigevent structure (not used, but required) - memset(&sevp, 0, sizeof(sevp)); - sevp.sigev_notify = SIGEV_NONE; - - // Start asynchronous resolution - int start_result = getaddrinfo_a(GAI_NOWAIT, requests, 1, &sevp); - if (start_result != 0) { return start_result; } - - // Wait for completion with timeout - int wait_result = - gai_suspend((const struct gaicb *const *)requests, 1, &timeout); - - if (wait_result == 0 || wait_result == EAI_ALLDONE) { - // Completed successfully, get the result - int gai_result = gai_error(&request); - if (gai_result == 0) { - *res = request.ar_result; - return 0; - } else { - // Clean up on error - if (request.ar_result) { freeaddrinfo(request.ar_result); } - return gai_result; - } - } else if (wait_result == EAI_AGAIN) { - // Timeout occurred, cancel the request - gai_cancel(&request); - return EAI_AGAIN; - } else { - // Other error occurred - gai_cancel(&request); - return wait_result; - } #else - // Fallback implementation using thread-based timeout for other Unix systems + // Fallback implementation using thread-based timeout for other Unix systems. + // + // The previous Linux/glibc path used getaddrinfo_a(GAI_NOWAIT) with a + // stack-local gaicb. On timeout it called gai_cancel(), which is non- + // blocking and may return EAI_NOTCANCELED -- the resolver worker would + // then write back to the destroyed stack frame after this function had + // already returned (#2431). The std::thread + shared_ptr fallback below + // is correct for the same reason it works on other platforms: the + // worker captures shared ownership of the state, so it stays alive as + // long as anyone (caller or worker) still holds a reference. struct GetAddrInfoState { ~GetAddrInfoState() {