llvm-project
7580d1ab - [sanitizer] Close per-thread glibc resolver state on thread exit (#242571)

Commit
11 hours ago
[sanitizer] Close per-thread glibc resolver state on thread exit (#242571) In glibc, DNS lookups (such as `getaddrinfo()` and `res_query()`) allocate per-thread nameserver address structures in `_res` (`_res._u._ext.nsaddrs`) and free them in `res_thread_freeres()` during `__libc_thread_freeres()`, after pthread TSD destructors have finished. Because ASan, LSan, and HWASan unregister the exiting thread in their pthread TSD destructors during `__nptl_deallocate_tsd()`, LSan stops scanning that thread's TLS before `res_thread_freeres()` runs. If a leak check runs in that window (for example, when the main thread exits while a detached worker thread is finishing), LSan reports a false-positive 28-byte leak (`sizeof(struct sockaddr_in6)`) from `__res_context_send` or `update_from_conf`. In `ClearDlerror()`, if `_res.nscount > 0`, call `res_nclose(&_res)` and reset `_res.options = 0` (matching glibc's `res_thread_freeres()`, glibc BZ #434) before unregistering the thread. Resetting `_res.options = 0` ensures that if a subsequent TSD destructor invokes the resolver after `res_nclose(&_res)` freed `nsaddrs` and detached `resolv_conf`, `maybe_init()` re-initializes `_res` instead of dereferencing a null `nsaddrs` pointer in `sock_eq()`. Unlike a runtime LSan suppression (alternative to #238901, suggested by @vitalybuka), freeing `_res` before thread unregistration avoids symbolizer initialization when no other leaks are present, works without `libc`/`libresolv` debug symbols (`symbolize=0`), and covers both IPv4 (`__res_context_send`) and IPv6 (`update_from_conf`) nameserver allocations. Assisted-by: Automated tooling, human reviewed.
Author
Parents
Loading