From 16f9d4a68d9b405da7871adc45d560c921ac1fd2 Mon Sep 17 00:00:00 2001 From: Cosmin Polifronie <31697380+cosminpolifronie@users.noreply.github.com> Date: Fri, 16 Oct 2026 00:53:29 +0300 Subject: [PATCH] Avoid getaddrinfo_a under ThreadSanitizer (#2631) glibc runs getaddrinfo_a() lookups in a thread it creates internally, bypassing the pthread_create interceptor, so TSan never initializes that thread and it crashes on its first allocation. Detect TSan (GCC's __SANITIZE_THREAD__ / Clang's __has_feature(thread_sanitizer)) and use the existing std::thread-based fallback instead, which keeps the lookup timeout working. Non-TSan builds are unchanged. --- httplib.h | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/httplib.h b/httplib.h index 906f8264..1dca2c8f 100644 --- a/httplib.h +++ b/httplib.h @@ -18,6 +18,14 @@ #endif #endif +#if defined(__SANITIZE_THREAD__) +#define CPPHTTPLIB_THREAD_SANITIZER +#elif defined(__has_feature) +#if __has_feature(thread_sanitizer) +#define CPPHTTPLIB_THREAD_SANITIZER +#endif +#endif + /* * Configuration */ @@ -7017,7 +7025,9 @@ 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)) + (__GLIBC__ > 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ >= 2)) && \ + !defined(CPPHTTPLIB_THREAD_SANITIZER) + // Skipped under TSan: glibc's internal resolver thread is invisible to it. // #2431: gai_cancel() is non-blocking and may return EAI_NOTCANCELED while // the resolver worker still references the stack-local gaicb. The cancel // path therefore waits (gai_suspend with no timeout) for the worker to