]> git.ipfire.org Git - thirdparty/bind9.git/commitdiff
Use hashmap when parsing a message
authorOndřej Surý <ondrej@isc.org>
Mon, 11 Sep 2023 08:35:28 +0000 (10:35 +0200)
committerMichał Kępień <michal@isc.org>
Fri, 5 Jan 2024 10:35:25 +0000 (11:35 +0100)
When parsing messages use a hashmap instead of a linear search to reduce
the amount of work done in findname when there's more than one name in
the section.

There are two hashmaps:

1) hashmap for owner names - that's constructed for each section when we
hit the second name in the section and destroyed right after parsing
that section;

2) per-name hashmap - for each name in the section, we construct a new
hashmap for that name if there are more than one rdataset for that
particular name.

lib/dns/include/dns/message.h
lib/dns/include/dns/name.h
lib/dns/message.c

index dc0c05846f6d3609ca3f72beb4caccc55c9aa6de..24acd4b8dc04c635c8d00d4d026b59e72ed40f20 100644 (file)
@@ -859,27 +859,6 @@ dns_message_findtype(const dns_name_t *name, dns_rdatatype_t type,
  *\li  #ISC_R_NOTFOUND         -- the desired type does not exist.
  */
 
-isc_result_t
-dns_message_find(const dns_name_t *name, dns_rdataclass_t rdclass,
-                dns_rdatatype_t type, dns_rdatatype_t covers,
-                dns_rdataset_t **rdataset);
-/*%<
- * Search the name for the specified rdclass and type.  If it is found,
- * *rdataset is filled in with a pointer to that rdataset.
- *
- * Requires:
- *\li  if '**rdataset' is non-NULL, *rdataset needs to be NULL.
- *
- *\li  'type' be a valid type, and NOT dns_rdatatype_any.
- *
- *\li  If 'type' is dns_rdatatype_rrsig, 'covers' must be a valid type.
- *     Otherwise it should be 0.
- *
- * Returns:
- *\li  #ISC_R_SUCCESS          -- all is well.
- *\li  #ISC_R_NOTFOUND         -- the desired type does not exist.
- */
-
 void
 dns_message_addname(dns_message_t *msg, dns_name_t *name,
                    dns_section_t section);
index d0d92bbe518bd5460f1c14cbd0c59d900d0cf89b..7a3ae95477688e099cfec0bcaaaae42a63f209c9 100644 (file)
@@ -68,6 +68,7 @@
 #include <stdio.h>
 
 #include <isc/buffer.h>
+#include <isc/hashmap.h>
 #include <isc/lang.h>
 #include <isc/magic.h>
 #include <isc/region.h> /* Required for storage size of dns_label_t. */
@@ -119,6 +120,7 @@ struct dns_name {
        isc_buffer_t  *buffer;
        ISC_LINK(dns_name_t) link;
        ISC_LIST(dns_rdataset_t) list;
+       isc_hashmap_t *hashmap;
 };
 
 #define DNS_NAME_MAGIC   ISC_MAGIC('D', 'N', 'S', 'n')
index c85e579b02ff8bd2fa15309b23aa9462cca83bbc..8280aa287fa3e6c242f0b721ebf4f7b6b2963d51 100644 (file)
@@ -22,6 +22,8 @@
 #include <stdbool.h>
 
 #include <isc/buffer.h>
+#include <isc/hash.h>
+#include <isc/hashmap.h>
 #include <isc/mem.h>
 #include <isc/result.h>
 #include <isc/string.h>
@@ -779,6 +781,11 @@ ISC_REFCOUNT_TRACE_IMPL(dns_message, dns__message_destroy);
 ISC_REFCOUNT_IMPL(dns_message, dns__message_destroy);
 #endif
 
+static bool
+name_match(void *node, const void *key) {
+       return (dns_name_equal(node, key));
+}
+
 static isc_result_t
 findname(dns_name_t **foundname, const dns_name_t *target,
         dns_namelist_t *section) {
@@ -796,26 +803,25 @@ findname(dns_name_t **foundname, const dns_name_t *target,
        return (ISC_R_NOTFOUND);
 }
 
-isc_result_t
-dns_message_find(const dns_name_t *name, dns_rdataclass_t rdclass,
-                dns_rdatatype_t type, dns_rdatatype_t covers,
-                dns_rdataset_t **rdatasetp) {
-       dns_rdataset_t *rds = NULL;
+static uint32_t
+rds_hash(dns_rdataset_t *rds) {
+       isc_hash32_t state;
 
-       REQUIRE(name != NULL);
-       REQUIRE(rdatasetp == NULL || *rdatasetp == NULL);
+       isc_hash32_init(&state);
+       isc_hash32_hash(&state, &rds->rdclass, sizeof(rds->rdclass), true);
+       isc_hash32_hash(&state, &rds->type, sizeof(rds->type), true);
+       isc_hash32_hash(&state, &rds->covers, sizeof(rds->covers), true);
 
-       ISC_LIST_FOREACH_REV (name->list, rds, link) {
-               if (rds->rdclass == rdclass && rds->type == type &&
-                   rds->covers == covers)
-               {
-                       SET_IF_NOT_NULL(rdatasetp, rds);
+       return (isc_hash32_finalize(&state));
+}
 
-                       return (ISC_R_SUCCESS);
-               }
-       }
+static bool
+rds_match(void *node, const void *key0) {
+       const dns_rdataset_t *rds = node;
+       const dns_rdataset_t *key = key0;
 
-       return (ISC_R_NOTFOUND);
+       return (rds->rdclass == key->rdclass && rds->type == key->type &&
+               rds->covers == key->covers);
 }
 
 isc_result_t
@@ -939,22 +945,38 @@ getrdata(isc_buffer_t *source, dns_message_t *msg, dns_decompress_t dctx,
                }                            \
        } while (0)
 
+static void
+cleanup_name_hashmaps(dns_namelist_t *section) {
+       dns_name_t *name = NULL;
+       ISC_LIST_FOREACH (*section, name, link) {
+               if (name->hashmap != NULL) {
+                       isc_hashmap_destroy(&name->hashmap);
+               }
+       }
+}
+
 static isc_result_t
 getquestions(isc_buffer_t *source, dns_message_t *msg, dns_decompress_t dctx,
             unsigned int options) {
        isc_region_t r;
        unsigned int count;
        dns_name_t *name = NULL;
-       dns_name_t *name2 = NULL;
+       dns_name_t *found_name = NULL;
        dns_rdataset_t *rdataset = NULL;
        dns_rdatalist_t *rdatalist = NULL;
-       isc_result_t result;
+       isc_result_t result = ISC_R_SUCCESS;
        dns_rdatatype_t rdtype;
        dns_rdataclass_t rdclass;
        dns_namelist_t *section = &msg->sections[DNS_SECTION_QUESTION];
        bool best_effort = ((options & DNS_MESSAGEPARSE_BESTEFFORT) != 0);
        bool seen_problem = false;
        bool free_name = false;
+       bool free_hashmaps = false;
+       isc_hashmap_t *name_map = NULL;
+
+       if (msg->counts[DNS_SECTION_QUESTION] > 1) {
+               isc_hashmap_create(msg->mctx, 1, &name_map);
+       }
 
        for (count = 0; count < msg->counts[DNS_SECTION_QUESTION]; count++) {
                name = NULL;
@@ -972,13 +994,21 @@ getquestions(isc_buffer_t *source, dns_message_t *msg, dns_decompress_t dctx,
                        goto cleanup;
                }
 
+               /* If there is only one QNAME, skip the duplicity checks */
+               if (name_map == NULL) {
+                       result = ISC_R_SUCCESS;
+                       goto skip_name_check;
+               }
+
                /*
                 * Run through the section, looking to see if this name
                 * is already there.  If it is found, put back the allocated
                 * name since we no longer need it, and set our name pointer
                 * to point to the name we found.
                 */
-               result = findname(&name2, name, section);
+               result = isc_hashmap_add(name_map, dns_name_hash(name),
+                                        name_match, name, name,
+                                        (void **)&found_name);
 
                /*
                 * If it is the first name in the section, accept it.
@@ -990,19 +1020,25 @@ getquestions(isc_buffer_t *source, dns_message_t *msg, dns_decompress_t dctx,
                 * this should be legal or not.  In either case we no longer
                 * need this name pointer.
                 */
-               if (result != ISC_R_SUCCESS) {
+       skip_name_check:
+               switch (result) {
+               case ISC_R_SUCCESS:
                        if (!ISC_LIST_EMPTY(*section)) {
                                DO_ERROR(DNS_R_FORMERR);
                        }
                        ISC_LIST_APPEND(*section, name, link);
-                       free_name = false;
-               } else {
+                       break;
+               case ISC_R_EXISTS:
                        dns_message_puttempname(msg, &name);
-                       name = name2;
-                       name2 = NULL;
-                       free_name = false;
+                       name = found_name;
+                       found_name = NULL;
+                       break;
+               default:
+                       UNREACHABLE();
                }
 
+               free_name = false;
+
                /*
                 * Get type and class.
                 */
@@ -1032,53 +1068,83 @@ getquestions(isc_buffer_t *source, dns_message_t *msg, dns_decompress_t dctx,
                        msg->tkey = 1;
                }
 
-               /*
-                * Can't ask the same question twice.
-                */
-               result = dns_message_find(name, rdclass, rdtype, 0, NULL);
-               if (result == ISC_R_SUCCESS) {
-                       DO_ERROR(DNS_R_FORMERR);
-               }
-
                /*
                 * Allocate a new rdatalist.
                 */
                rdatalist = newrdatalist(msg);
-               if (rdatalist == NULL) {
-                       result = ISC_R_NOMEMORY;
-                       goto cleanup;
-               }
-               rdataset = isc_mempool_get(msg->rdspool);
+               rdatalist->type = rdtype;
+               rdatalist->rdclass = rdclass;
+               rdatalist->covers = 0;
 
                /*
                 * Convert rdatalist to rdataset, and attach the latter to
                 * the name.
                 */
-               rdatalist->type = rdtype;
-               rdatalist->rdclass = rdclass;
-
-               dns_rdataset_init(rdataset);
+               dns_message_gettemprdataset(msg, &rdataset);
                dns_rdatalist_tordataset(rdatalist, rdataset);
 
                rdataset->attributes |= DNS_RDATASETATTR_QUESTION;
 
+               /*
+                * Skip the duplicity check for first rdataset
+                */
+               if (ISC_LIST_EMPTY(name->list)) {
+                       result = ISC_R_SUCCESS;
+                       goto skip_rds_check;
+               }
+
+               /*
+                * Can't ask the same question twice.
+                */
+               if (name->hashmap == NULL) {
+                       isc_hashmap_create(msg->mctx, 1, &name->hashmap);
+                       free_hashmaps = true;
+
+                       INSIST(ISC_LIST_HEAD(name->list) ==
+                              ISC_LIST_TAIL(name->list));
+
+                       dns_rdataset_t *old_rdataset =
+                               ISC_LIST_HEAD(name->list);
+
+                       result = isc_hashmap_add(
+                               name->hashmap, rds_hash(old_rdataset),
+                               rds_match, old_rdataset, old_rdataset, NULL);
+
+                       INSIST(result == ISC_R_SUCCESS);
+               }
+               result = isc_hashmap_add(name->hashmap, rds_hash(rdataset),
+                                        rds_match, rdataset, rdataset, NULL);
+               if (result == ISC_R_EXISTS) {
+                       DO_ERROR(DNS_R_FORMERR);
+               }
+
+       skip_rds_check:
                ISC_LIST_APPEND(name->list, rdataset, link);
+
                rdataset = NULL;
        }
 
        if (seen_problem) {
-               return (DNS_R_RECOVERABLE);
+               result = DNS_R_RECOVERABLE;
        }
-       return (ISC_R_SUCCESS);
 
 cleanup:
        if (rdataset != NULL) {
                dns_message_puttemprdataset(msg, &rdataset);
        }
+
        if (free_name) {
                dns_message_puttempname(msg, &name);
        }
 
+       if (free_hashmaps) {
+               cleanup_name_hashmaps(section);
+       }
+
+       if (name_map != NULL) {
+               isc_hashmap_destroy(&name_map);
+       }
+
        return (result);
 }
 
@@ -1105,7 +1171,6 @@ auth_signed(dns_namelist_t *section) {
        ISC_LIST_FOREACH (*section, name, link) {
                int auth_dnssec = 0, auth_rrsig = 0;
                dns_rdataset_t *rds = NULL;
-
                ISC_LIST_FOREACH (name->list, rds, link) {
                        switch (rds->type) {
                        case dns_rdatatype_ds:
@@ -1152,19 +1217,26 @@ getsection(isc_buffer_t *source, dns_message_t *msg, dns_decompress_t dctx,
        isc_region_t r;
        unsigned int count, rdatalen;
        dns_name_t *name = NULL;
-       dns_name_t *name2 = NULL;
+       dns_name_t *found_name = NULL;
        dns_rdataset_t *rdataset = NULL;
+       dns_rdataset_t *found_rdataset = NULL;
        dns_rdatalist_t *rdatalist = NULL;
-       isc_result_t result;
+       isc_result_t result = ISC_R_SUCCESS;
        dns_rdatatype_t rdtype, covers;
        dns_rdataclass_t rdclass;
        dns_rdata_t *rdata = NULL;
        dns_ttl_t ttl;
        dns_namelist_t *section = &msg->sections[sectionid];
-       bool free_name = false, free_rdataset = false, seen_problem = false;
+       bool free_name = false, seen_problem = false;
+       bool free_hashmaps = false;
        bool preserve_order = ((options & DNS_MESSAGEPARSE_PRESERVEORDER) != 0);
        bool best_effort = ((options & DNS_MESSAGEPARSE_BESTEFFORT) != 0);
        bool isedns, issigzero, istsig;
+       isc_hashmap_t *name_map = NULL;
+
+       if (msg->counts[sectionid] > 1) {
+               isc_hashmap_create(msg->mctx, 1, &name_map);
+       }
 
        for (count = 0; count < msg->counts[sectionid]; count++) {
                int recstart = source->current;
@@ -1172,7 +1244,6 @@ getsection(isc_buffer_t *source, dns_message_t *msg, dns_decompress_t dctx,
 
                skip_name_search = false;
                skip_type_search = false;
-               free_rdataset = false;
                isedns = false;
                issigzero = false;
                istsig = false;
@@ -1212,8 +1283,8 @@ getsection(isc_buffer_t *source, dns_message_t *msg, dns_decompress_t dctx,
                if (msg->rdclass_set == 0 &&
                    rdtype != dns_rdatatype_opt &&  /* class is UDP SIZE */
                    rdtype != dns_rdatatype_tsig && /* class is ANY */
-                   rdtype != dns_rdatatype_tkey)
-               { /* class is undefined */
+                   rdtype != dns_rdatatype_tkey)   /* class is undefined */
+               {
                        msg->rdclass = rdclass;
                        msg->rdclass_set = 1;
                }
@@ -1412,61 +1483,128 @@ getsection(isc_buffer_t *source, dns_message_t *msg, dns_decompress_t dctx,
                                free_name = false;
                        }
                } else {
+                       if (name_map == NULL) {
+                               result = ISC_R_SUCCESS;
+                               goto skip_name_check;
+                       }
+
                        /*
                         * Run through the section, looking to see if this name
                         * is already there.  If it is found, put back the
                         * allocated name since we no longer need it, and set
                         * our name pointer to point to the name we found.
                         */
-                       result = findname(&name2, name, section);
+                       result = isc_hashmap_add(name_map, dns_name_hash(name),
+                                                name_match, name, name,
+                                                (void **)&found_name);
 
                        /*
                         * If it is a new name, append to the section.
                         */
-                       if (result == ISC_R_SUCCESS) {
-                               dns_message_puttempname(msg, &name);
-                               name = name2;
-                       } else {
+               skip_name_check:
+                       switch (result) {
+                       case ISC_R_SUCCESS:
                                ISC_LIST_APPEND(*section, name, link);
+                               break;
+                       case ISC_R_EXISTS:
+                               dns_message_puttempname(msg, &name);
+                               name = found_name;
+                               found_name = NULL;
+                               break;
+                       default:
+                               UNREACHABLE();
                        }
                        free_name = false;
                }
 
+               rdatalist = newrdatalist(msg);
+               rdatalist->type = rdtype;
+               rdatalist->covers = covers;
+               rdatalist->rdclass = rdclass;
+               rdatalist->ttl = ttl;
+
+               dns_message_gettemprdataset(msg, &rdataset);
+               dns_rdatalist_tordataset(rdatalist, rdataset);
+               dns_rdataset_setownercase(rdataset, name);
+               rdatalist = NULL;
+
                /*
                 * Search name for the particular type and class.
                 * Skip this stage if in update mode or this is a meta-type.
                 */
-               if (preserve_order || msg->opcode == dns_opcode_update ||
-                   skip_type_search)
+               if (isedns || istsig || issigzero) {
+                       /* Skip adding the rdataset to the tables */
+               } else if (preserve_order || msg->opcode == dns_opcode_update ||
+                          skip_type_search)
                {
-                       result = ISC_R_NOTFOUND;
+                       result = ISC_R_SUCCESS;
+
+                       ISC_LIST_APPEND(name->list, rdataset, link);
                } else {
                        /*
                         * If this is a type that can only occur in
                         * the question section, fail.
                         */
                        if (dns_rdatatype_questiononly(rdtype)) {
+                               dns_message_puttemprdataset(msg, &rdataset);
                                DO_ERROR(DNS_R_FORMERR);
                        }
 
-                       rdataset = NULL;
-                       result = dns_message_find(name, rdclass, rdtype, covers,
-                                                 &rdataset);
-               }
+                       if (ISC_LIST_EMPTY(name->list)) {
+                               result = ISC_R_SUCCESS;
+                               goto skip_rds_check;
+                       }
+
+                       if (name->hashmap == NULL) {
+                               isc_hashmap_create(msg->mctx, 1,
+                                                  &name->hashmap);
+                               free_hashmaps = true;
+
+                               INSIST(ISC_LIST_HEAD(name->list) ==
+                                      ISC_LIST_TAIL(name->list));
+
+                               dns_rdataset_t *old_rdataset =
+                                       ISC_LIST_HEAD(name->list);
+
+                               result = isc_hashmap_add(
+                                       name->hashmap, rds_hash(old_rdataset),
+                                       rds_match, old_rdataset, old_rdataset,
+                                       NULL);
+
+                               INSIST(result == ISC_R_SUCCESS);
+                       }
+
+                       result = isc_hashmap_add(
+                               name->hashmap, rds_hash(rdataset), rds_match,
+                               rdataset, rdataset, (void **)&found_rdataset);
+
+                       /*
+                        * If we found an rdataset that matches, we need to
+                        * append this rdata to that set.  If we did not, we
+                        * need to create a new rdatalist, store the important
+                        * bits there, convert it to an rdataset, and link the
+                        * latter to the name. Yuck.  When appending, make
+                        * certain that the type isn't a singleton type, such as
+                        * SOA or CNAME.
+                        *
+                        * Note that this check will be bypassed when preserving
+                        * order, the opcode is an update, or the type search is
+                        * skipped.
+                        */
+               skip_rds_check:
+                       switch (result) {
+                       case ISC_R_EXISTS:
+                               /* Free the rdataset we used as the key */
+                               dns__message_putassociatedrdataset(msg,
+                                                                  &rdataset);
+                               rdataset = found_rdataset;
+
+                               result = ISC_R_SUCCESS;
+
+                               if (!dns_rdatatype_issingleton(rdtype)) {
+                                       break;
+                               }
 
-               /*
-                * If we found an rdataset that matches, we need to
-                * append this rdata to that set.  If we did not, we need
-                * to create a new rdatalist, store the important bits there,
-                * convert it to an rdataset, and link the latter to the name.
-                * Yuck.  When appending, make certain that the type isn't
-                * a singleton type, such as SOA or CNAME.
-                *
-                * Note that this check will be bypassed when preserving order,
-                * the opcode is an update, or the type search is skipped.
-                */
-               if (result == ISC_R_SUCCESS) {
-                       if (dns_rdatatype_issingleton(rdtype)) {
                                dns_rdata_t *first;
                                dns_rdatalist_fromrdataset(rdataset,
                                                           &rdatalist);
@@ -1475,31 +1613,12 @@ getsection(isc_buffer_t *source, dns_message_t *msg, dns_decompress_t dctx,
                                if (dns_rdata_compare(rdata, first) != 0) {
                                        DO_ERROR(DNS_R_FORMERR);
                                }
-                       }
-               }
-
-               if (result == ISC_R_NOTFOUND) {
-                       rdataset = isc_mempool_get(msg->rdspool);
-                       free_rdataset = true;
-
-                       rdatalist = newrdatalist(msg);
-                       if (rdatalist == NULL) {
-                               result = ISC_R_NOMEMORY;
-                               goto cleanup;
-                       }
-
-                       rdatalist->type = rdtype;
-                       rdatalist->covers = covers;
-                       rdatalist->rdclass = rdclass;
-                       rdatalist->ttl = ttl;
-
-                       dns_rdataset_init(rdataset);
-                       dns_rdatalist_tordataset(rdatalist, rdataset);
-                       dns_rdataset_setownercase(rdataset, name);
-
-                       if (!isedns && !istsig && !issigzero) {
+                               break;
+                       case ISC_R_SUCCESS:
                                ISC_LIST_APPEND(name->list, rdataset, link);
-                               free_rdataset = false;
+                               break;
+                       default:
+                               UNREACHABLE();
                        }
                }
 
@@ -1535,7 +1654,6 @@ getsection(isc_buffer_t *source, dns_message_t *msg, dns_decompress_t dctx,
 
                        msg->opt = rdataset;
                        rdataset = NULL;
-                       free_rdataset = false;
                        ercode = (dns_rcode_t)((msg->opt->ttl &
                                                DNS_MESSAGE_EDNSRCODE_MASK) >>
                                               20);
@@ -1547,7 +1665,6 @@ getsection(isc_buffer_t *source, dns_message_t *msg, dns_decompress_t dctx,
                        msg->sig0name = name;
                        msg->sigstart = recstart;
                        rdataset = NULL;
-                       free_rdataset = false;
                        free_name = false;
                } else if (istsig) {
                        msg->tsig = rdataset;
@@ -1558,7 +1675,6 @@ getsection(isc_buffer_t *source, dns_message_t *msg, dns_decompress_t dctx,
                         */
                        msg->tsigname->attributes.nocompress = true;
                        rdataset = NULL;
-                       free_rdataset = false;
                        free_name = false;
                }
 
@@ -1566,14 +1682,11 @@ getsection(isc_buffer_t *source, dns_message_t *msg, dns_decompress_t dctx,
                        if (free_name) {
                                dns_message_puttempname(msg, &name);
                        }
-                       if (free_rdataset) {
-                               dns__message_putassociatedrdataset(msg,
-                                                                  &rdataset);
-                       }
-                       free_name = free_rdataset = false;
+                       free_name = false;
                }
                INSIST(!free_name);
-               INSIST(!free_rdataset);
+
+               rdataset = NULL;
        }
 
        /*
@@ -1591,16 +1704,20 @@ getsection(isc_buffer_t *source, dns_message_t *msg, dns_decompress_t dctx,
        }
 
        if (seen_problem) {
-               return (DNS_R_RECOVERABLE);
+               result = DNS_R_RECOVERABLE;
        }
-       return (ISC_R_SUCCESS);
 
 cleanup:
        if (free_name) {
                dns_message_puttempname(msg, &name);
        }
-       if (free_rdataset) {
-               dns__message_putassociatedrdataset(msg, &rdataset);
+
+       if (free_hashmaps) {
+               cleanup_name_hashmaps(section);
+       }
+
+       if (name_map != NULL) {
+               isc_hashmap_destroy(&name_map);
        }
 
        return (result);
@@ -1661,6 +1778,7 @@ dns_message_parse(dns_message_t *msg, isc_buffer_t *source,
        dctx = DNS_DECOMPRESS_ALWAYS;
 
        ret = getquestions(source, msg, dctx, options);
+
        if (ret == ISC_R_UNEXPECTEDEND && ignore_tc) {
                goto truncated;
        }
@@ -2349,15 +2467,13 @@ dns_message_renderreset(dns_message_t *msg) {
                dns_message_puttempname(msg, &msg->tsigname);
        }
        if (msg->tsig != NULL) {
-               dns_rdataset_disassociate(msg->tsig);
-               dns_message_puttemprdataset(msg, &msg->tsig);
+               dns__message_putassociatedrdataset(msg, &msg->tsig);
        }
        if (msg->sig0name != NULL) {
                dns_message_puttempname(msg, &msg->sig0name);
        }
        if (msg->sig0 != NULL) {
-               dns_rdataset_disassociate(msg->sig0);
-               dns_message_puttemprdataset(msg, &msg->sig0);
+               dns__message_putassociatedrdataset(msg, &msg->sig0);
        }
 }
 
@@ -2406,7 +2522,7 @@ dns_message_findname(dns_message_t *msg, dns_section_t section,
                     const dns_name_t *target, dns_rdatatype_t type,
                     dns_rdatatype_t covers, dns_name_t **name,
                     dns_rdataset_t **rdataset) {
-       dns_name_t *foundname;
+       dns_name_t *foundname = NULL;
        isc_result_t result;
 
        /*
@@ -2524,6 +2640,10 @@ dns_message_puttempname(dns_message_t *msg, dns_name_t **itemp) {
        REQUIRE(!ISC_LINK_LINKED(item, link));
        REQUIRE(ISC_LIST_HEAD(item->list) == NULL);
 
+       if (item->hashmap != NULL) {
+               isc_hashmap_destroy(&item->hashmap);
+       }
+
        /*
         * we need to check this in case dns_name_dup() was used.
         */
@@ -2551,8 +2671,7 @@ dns_message_puttemprdata(dns_message_t *msg, dns_rdata_t **item) {
 static void
 dns__message_putassociatedrdataset(dns_message_t *msg, dns_rdataset_t **item) {
        dns_rdataset_disassociate(*item);
-       isc_mempool_put(msg->rdspool, *item);
-       *item = NULL;
+       dns_message_puttemprdataset(msg, item);
 }
 
 void
@@ -2730,8 +2849,7 @@ dns_message_setopt(dns_message_t *msg, dns_rdataset_t *opt) {
        return (ISC_R_SUCCESS);
 
 cleanup:
-       dns_rdataset_disassociate(opt);
-       dns_message_puttemprdataset(msg, &opt);
+       dns__message_putassociatedrdataset(msg, &opt);
        return (result);
 }