dns: remove the remaining unsafe from the resolver module
What
Same programme as #40055 / #40135 / #40136 / #40139 / #40187, applied to DNS: src/runtime/dns_jsc/dns.rs 259 → 0, cares_jsc.rs 38 → 0, dns_sd.rs 43 → 0, by giving the C libraries typed, owning wrappers one layer down instead of open-coding pointer handling in the resolver.
- c-ares (
bun_cares_sys):OwnedChannel(Drop =ares_destroy) created withChannel::init(ThisPtr<C: ChannelOwner>); queries take aBox<H: QueryHandler | AddrInfoHandler | HostentHandler | NameInfoHandler>and hand it back exactly once through one generic trampoline per callback shape (c-ares guarantees one callback on success /ECANCELLED/EDESTRUCTION); replies areAresBox<T: AresAllocated>freed with the right deallocator;struct_hostent/ reply structs expose safe accessors and iterators instead of raw NULL-terminated arrays;set_servers,get_sockaddr(now returns asockaddr_storage— the old code wrote asockaddr_in6through a 16-byte&mut sockaddr),inet_pton,parse_*are safe. - Resolver ownership:
Resolveris#[derive(RefCounted)]; every in-flight lookup holdsOption<RefPtr<Resolver>>(wasIntrusiveRc::init_ref), the armed timeout timer's ref is atimer_refslot; host fns / dispatch takethis: ThisPtr<Self>. The per-type pending caches hold their waiters by value (Vec<Option<PendingEntry<L>>>+ occupancy mask) instead of intrusivenext/tailpointers intoHiveArrayslots; coalescing, the 32-entry limit, waiter order andrequest_completedpoints are unchanged. - Process-wide connect-path cache (
internal): requests areOwnedThis<Request>in the locked global cache; C (usockets, QUIC) receivesThisPtr<Request>; cross-thread holders areBackRef<Request, Mut>;refcount/validare atomics,notifya guarded vec, the result anOnceLock<AddrInfoResult>. The C-facingaddrinfo_result{,_entry}and theDnsWaitingSocket/DnsPendingConnectnotify handles live inbun_uws_sys::addrinfo/bun_http::H3(Send handles expose only the thread-safe notify; same-thread notification goes through the borrowed socket / owned box). AllBun__addrinfo_*,Bun__DNS__*,__bun_dns_prefetchareHOST_EXPORTs (the prefetch export now takes a length instead of treating install's non-terminated slice as aZStr). - libuv (Windows):
bun_libuv_sys::getaddrinfo(loop, Box<T: GetAddrInfoRequest>, ..)round-trips the box throughreq.data;InflightGetAddrInfo::cancel;UvAddrInfo(Drop =uv_freeaddrinfo);SocketPoll<T>for the c-ares fd polls. libinfo / dns_sd (macOS):bun_sys::dns_sd::{Connection, Query}with one reply trampoline; the shared connection is a thread-localRc. POSIX:bun_sys::net::AddrInfoList(ownedgetaddrinfolist),Address::from_sockaddr_bytes;bun_io::OwnedFilePoll. ManagedTask::new_boxed<T: RunOnce>; generator learnsOption<&CStr>;#[host_fn]this: ThisPtr<Self>receiver support andbun_ptr::OwnedThisare cherry-picked byte-for-byte from #40139.
Testing
Debug+ASAN: test/js/bun/dns (87), test/js/node/dns (171), all 27 test-dns* / test-worker-dns* / test-net-dns* node parallel tests, socket-dns-error, socket.test, websocket, node-http, fetch pass (fetch's root-permission cases and the 150 ms AbortSignal.timeout redirect case fail on any debug build here). Hand-driven: lookup via c-ares/libc/system backends + coalescing, resolve4/reverse/lookupService, Resolver.cancel() mid-query against a black-hole UDP socket (ECANCELLED), prefetch + getCacheStats, fetch through the connect-path cache, workers exiting/terminated with queries in flight, interior-NUL names — exit 0, no ASAN output. clippy clean on every touched crate; rust-check-all x86_64/aarch64-windows-msvc + aarch64-apple-darwin pass (Windows/macOS paths type-checked, not executed here). An additional adversarial review pass over the cache redesign and the cross-thread cache found no behavioural regressions; its latent findings are fixed in the second commit.
Follow-up (review): bun_dns::ResultAny is gone (native completions carry Option<&ResultList>; GetAddrInfoResult::to_list takes &bun_sys::net::AddrInfoList; Windows AddrInfoList::from_uv adopts the libuv block) — options_jsc.rs is now 0 unsafe too; the connect-path waiter lists live under GlobalCache's single lock (no nested Guarded), and an orphaned request whose refcount hits 0 is freed immediately; Backend/BackendDnsSd collapsed to a #[cfg(target_os="macos")] dns_sd: JsCell<QueryState> field; ManagedTask::new_owned retired in favour of new_boxed (RunTestsTask, QueuedEvent implement RunOnce); libuv cancel handle and dns_sd parent/child ordering are structural (Rc token / Rc<PrimaryRef>).