From 8de3716abd94f2abe760f8d64efe5fe03d479c99 Mon Sep 17 00:00:00 2001 From: bneradt Date: Wed, 17 Jun 2026 17:34:33 -0500 Subject: [PATCH] Fix pending HostDB DNS queue removal race A crash was observed while HostDB was probing pending DNS state for a request, with the stack unwinding through the DNS lookup path: #4 swoc::bwf::ExternalNames::operator()(...) at libswoc_1.5.15/include/swoc/bwf_base.h:610 #7 HostDBContinuation::do_dns(...) at src/iocore/hostdb/HostDB.cc:1352 #11 probe(...) at src/iocore/hostdb/HostDB.cc:581 The core showed an obviously corrupted ExternalNames this pointer while HostDB was allocating a continuation from the pending DNS path. The local signal cleanup path could edit the pending-DNS queue without the bucket lock, leaving stale revalidation readers able to walk links while they were being changed. This routes that cleanup through the locked pending-DNS removal helper and uses its result to decide whether the continuation still owns self-cleanup. This keeps queue membership checks and removals synchronized without changing the timeout path's lifetime behavior. --- src/iocore/hostdb/HostDB.cc | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/iocore/hostdb/HostDB.cc b/src/iocore/hostdb/HostDB.cc index fc7bc40fead..780de2a5d60 100644 --- a/src/iocore/hostdb/HostDB.cc +++ b/src/iocore/hostdb/HostDB.cc @@ -837,6 +837,7 @@ HostDBContinuation::dnsEvent(int event, HostEnt *e) // Event should be immediate or interval. if (!action.continuation) { // Nothing to do, give up. + bool cleanup_self = false; if (event == EVENT_INTERVAL) { // Timeout - clear all queries queued up for this FQDN because none of the other ones have sent an // actual DNS query. If the request rate is high enough this can cause a persistent queue where the @@ -846,9 +847,9 @@ HostDBContinuation::dnsEvent(int event, HostEnt *e) } else { // "local" signal to give up, usually due this being one of those "other" queries. // That generally means @a this has already been removed from the queue, but just in case... - hostDB.pending_dns_for_hash(hash.hash).remove(this); + cleanup_self = hostDB.remove_from_pending_dns_for_hash(hash.hash, this); } - if (hostDB.remove_from_pending_dns_for_hash(hash.hash, this)) { + if (cleanup_self) { hostdb_cont_free(this); } return EVENT_DONE;