diff --git a/CHANGES b/CHANGES
index fbd6bf4267..668eb23180 100644
--- a/CHANGES
+++ b/CHANGES
@@ -1,3 +1,6 @@
+4094. [bug] A race during shutdown or reconfiguration could
+ cause an assertion in mem.c. [RT #38979]
+
4093. [func] Dig now learns the SIT value from truncated
responses when it retries over TCP. [RT #39047]
diff --git a/doc/arm/notes.xml b/doc/arm/notes.xml
index 624e9d417f..9294996e35 100644
--- a/doc/arm/notes.xml
+++ b/doc/arm/notes.xml
@@ -581,6 +581,12 @@
in zt.c. [RT #37573]
+
+
+ A race during shutdown or reconfiguration could
+ cause an assertion failure in mem.c. [RT #38979]
+
+
diff --git a/lib/dns/resolver.c b/lib/dns/resolver.c
index e8e51155c5..aaa58846a5 100644
--- a/lib/dns/resolver.c
+++ b/lib/dns/resolver.c
@@ -533,6 +533,8 @@ static void add_bad(fetchctx_t *fctx, dns_adbaddrinfo_t *addrinfo,
static inline isc_result_t findnoqname(fetchctx_t *fctx, dns_name_t *name,
dns_rdatatype_t type,
dns_name_t **noqname);
+static void fctx_increference(fetchctx_t *fctx);
+static isc_boolean_t fctx_decreference(fetchctx_t *fctx);
/*%
* Increment resolver-related statistics counters.
@@ -815,10 +817,12 @@ fctx_startidletimer(fetchctx_t *fctx, isc_interval_t *interval) {
*/
#define fctx_stopidletimer fctx_starttimer
-
static inline void
resquery_destroy(resquery_t **queryp) {
+ dns_resolver_t *res;
+ isc_boolean_t empty;
resquery_t *query;
+ fetchctx_t *fctx;
REQUIRE(queryp != NULL);
query = *queryp;
@@ -826,15 +830,21 @@ resquery_destroy(resquery_t **queryp) {
INSIST(query->tcpsocket == NULL);
- query->fctx->nqueries--;
- if (SHUTTINGDOWN(query->fctx)) {
- dns_resolver_t *res = query->fctx->res;
- if (maybe_destroy(query->fctx, ISC_FALSE))
- empty_bucket(res);
- }
+ fctx = query->fctx;
+ res = fctx->res;
+
+ fctx->nqueries--;
+
+ LOCK(&res->buckets[fctx->bucketnum].lock);
+ empty = fctx_decreference(query->fctx);
+ UNLOCK(&res->buckets[fctx->bucketnum].lock);
+
query->magic = 0;
isc_mem_put(query->mctx, query, sizeof(*query));
*queryp = NULL;
+
+ if (empty)
+ empty_bucket(res);
}
static void
@@ -1621,6 +1631,7 @@ fctx_query(fetchctx_t *fctx, dns_adbaddrinfo_t *addrinfo,
}
query->dispentry = NULL;
+ fctx_increference(fctx);
query->fctx = fctx;
query->tsig = NULL;
query->tsigkey = NULL;
@@ -6970,10 +6981,21 @@ answer_response(fetchctx_t *fctx) {
return (result);
}
+static void
+fctx_increference(fetchctx_t *fctx) {
+ REQUIRE(VALID_FCTX(fctx));
+
+ LOCK(&fctx->res->buckets[fctx->bucketnum].lock);
+ fctx->references++;
+ UNLOCK(&fctx->res->buckets[fctx->bucketnum].lock);
+}
+
static isc_boolean_t
fctx_decreference(fetchctx_t *fctx) {
isc_boolean_t bucket_empty = ISC_FALSE;
+ REQUIRE(VALID_FCTX(fctx));
+
INSIST(fctx->references > 0);
fctx->references--;
if (fctx->references == 0) {
@@ -8209,9 +8231,7 @@ resquery_response(isc_task_t *task, isc_event_t *event) {
if (result != ISC_R_SUCCESS)
fctx_done(fctx, result, __LINE__);
else {
- LOCK(&fctx->res->buckets[fctx->bucketnum].lock);
- fctx->references++;
- UNLOCK(&fctx->res->buckets[fctx->bucketnum].lock);
+ fctx_increference(fctx);
result = fctx_stopidletimer(fctx);
if (result != ISC_R_SUCCESS)
fctx_done(fctx, result, __LINE__);