Each function queuing a do_nsfetch() call using isc_async_run() is
expected to increase the given zone's internal reference count
(zone->irefs), which is then correspondingly decreased in either
do_nsfetch() itself (when the dns_resolver_createfetch() fails) or in
nsfetch_done() (when recursion is finished).
However, do_nsfetch() can also return early if either the zone itself or
the relevant view's resolver object is being shut down. In that case,
do_nsfetch() simply returns without decreasing the internal reference
count for the zone. This leaves a dangling zone reference around, which
leads to hangs during named shutdown.
Fix by executing the same cleanup code for early returns from
do_nsfetch() as for a failed dns_resolver_createfetch() call in that
function as the reference count will not be decreased in nsfetch_done()
in any of these cases.
unsigned int options = DNS_FETCHOPT_UNSHARED | DNS_FETCHOPT_NOCACHED;
if (DNS_ZONE_FLAG(zone, DNS_ZONEFLG_EXITING)) {
- return;
+ result = ISC_R_SHUTTINGDOWN;
+ goto cleanup;
}
result = dns_view_getresolver(zone->view, &resolver);
if (result != ISC_R_SUCCESS) {
- return;
+ goto cleanup;
}
if (isc_log_wouldlog(dns_lctx, ISC_LOG_DEBUG(3))) {
dns_resolver_detach(&resolver);
+cleanup:
if (result != ISC_R_SUCCESS) {
dns_name_t *zname = dns_fixedname_name(&nsfetch->name);
bool free_needed;