Since macOS 26 (Tahoe), getaddrinfo() with AF_UNSPEC for a hostname whose DNS answer contains only A records (no AAAA) fails in forked child processes when the parent performed DNS resolution, or otherwise initialized os_log, before forking. This is a regression: the same code works on macOS 15.x and earlier.
The child crashes with EXC_BAD_ACCESS (KERN_INVALID_ADDRESS) inside the NAT64 synthesis path:
_os_log_preferences_refresh (libsystem_trace.dylib) <- faulting frame
os_log_type_enabled (libsystem_trace.dylib)
nw_path_access_agent_cache (Network)
_nw_path_update_is_viableTm / nw_path_snapshot_path / nw_path_evaluator_evaluate
nw_nat64_v4_address_requires_synthesis
_gai_nat64_second_pass (libsystem_info.dylib)
si_addrinfo -> getaddrinfo
Runtimes that install a SIGSEGV handler (Ruby, Python) do not die; instead the DNS helper thread spins at 100% CPU and the process hangs. We have also captured a parent-side variant where a later fork() deadlocks in the atfork prepare path itself: libSystem_atfork_prepare -> nw_path_prepare_fork -> _os_unfair_lock_lock_slow.
Minimal trigger in C:
os_log_t log = os_log_create("com.example.repro", "repro");
os_log(log, "init");
struct addrinfo hints = { .ai_family = AF_UNSPEC, .ai_socktype = SOCK_STREAM }, *res;
getaddrinfo("api.stripe.com", "443", &hints, &res); // parent: IPv4-only host
if (fork() == 0) {
getaddrinfo("api.stripe.com", "443", &hints, &res); // child: crashes in _os_log_preferences_refresh
_exit(0);
}
Observed behavior and boundaries:
Reproduces on 26.1 through 26.5.1 (25F80). Not reproducible on macOS 15.x.
Only AF_UNSPEC lookups of IPv4-only hostnames are affected. AF_INET hints, IPv6-capable hostnames (for example google.com), numeric literals, and localhost are all immune. AF_INET6-only lookups neither trigger nor prevent it.
The failure is all-or-nothing per parent process: once a parent is in the affected state, every forked child fails.
On 26.5.1 it reproduces most reliably when the process was exec'd over a prior os_log-using image (for example Ruby launched via bundle exec, where the bundler Ruby execs the target Ruby in the same process), and intermittently from a bare shell. On 26.1 even bare runs reproduced readily. This is consistent with per-process logging state surviving exec and then being inherited invalid across fork.
I understand that officially only async-signal-safe calls are supported between fork and exec. But this worked through macOS 15, and it breaks the pre-forking worker model used by major Ruby and Python frameworks (Resque, Unicorn, multiprocessing) on developer machines.
Filed as FB21364061 in December 2025, no response so far. Is this a known issue, and is a fix present or planned in macOS 26.6 or the macOS 27 beta?