Commit 5b528a86ac for bind
commit 5b528a86acc555bdd786b64f9d6fa83a6dbeaaff
Author: Alessio Podda <alessio@isc.org>
Date: Mon Aug 24 16:13:40 2026 +0200
Move count inside the header
Simplify rdatavec by always storing the count, even for tombstone
headers.
diff --git a/lib/dns/include/dns/rdatavec.h b/lib/dns/include/dns/rdatavec.h
index 4a80e96240..5cf3566114 100644
--- a/lib/dns/include/dns/rdatavec.h
+++ b/lib/dns/include/dns/rdatavec.h
@@ -82,6 +82,7 @@ struct dns_vecheader {
_Atomic(dns_trust_t) trust;
dns_typepair_t typepair;
+ uint16_t count;
isc_refcount_t references;
diff --git a/lib/dns/qpzone.c b/lib/dns/qpzone.c
index 9ab890fbe2..69078fb7a3 100644
--- a/lib/dns/qpzone.c
+++ b/lib/dns/qpzone.c
@@ -1011,7 +1011,7 @@ static dns_vecheader_t *
first_existing_header(dns_vectop_t *top, uint32_t serial) {
ISC_SLIST_FOREACH(header, top->headers, next_header) {
if (header->serial <= serial && !IGNORE(header)) {
- if (EXISTS(header)) {
+ if (header->count != 0) {
return header;
}
break;
@@ -1893,16 +1893,18 @@ recordsize(dns_vecheader_t *header, unsigned int namelen) {
static void
maybe_update_recordsandsize(bool add, qpz_version_t *version,
dns_vecheader_t *header, unsigned int namelen) {
- if (!EXISTS(header)) {
+ unsigned int count = header->count;
+
+ if (count == 0) {
return;
}
RWLOCK(&version->rwlock, isc_rwlocktype_write);
if (add) {
- version->records += dns_rdatavec_count(header);
+ version->records += count;
version->xfrsize += recordsize(header, namelen);
} else {
- version->records -= dns_rdatavec_count(header);
+ version->records -= count;
version->xfrsize -= recordsize(header, namelen);
}
RWUNLOCK(&version->rwlock, isc_rwlocktype_write);
@@ -1971,7 +1973,7 @@ add(qpzonedb_t *qpdb, qpznode_t *node, const dns_name_t *nodename,
* we'll try to create a new rdataset that is the union
* of 'newheader' and 'header'.
*/
- if (merge && EXISTS(header)) {
+ if (merge && header->count != 0) {
unsigned int flags = 0;
INSIST(version->serial >= header->serial);
merged = NULL;
@@ -2091,7 +2093,7 @@ add(qpzonedb_t *qpdb, qpznode_t *node, const dns_name_t *nodename,
*
* If we're trying to delete the type, don't bother.
*/
- if (!EXISTS(newheader)) {
+ if (newheader->count == 0) {
dns_vecheader_unref(newheader);
return DNS_R_UNCHANGED;
}
@@ -5128,7 +5130,7 @@ qpzone_subtractrdataset(dns_db_t *db, dns_dbnode_t *dbnode,
}
}
}
- if (header != NULL && EXISTS(header)) {
+ if (header != NULL && header->count != 0) {
unsigned int flags = 0;
subresult = NULL;
result = ISC_R_SUCCESS;
diff --git a/lib/dns/rdatavec.c b/lib/dns/rdatavec.c
index 19d7ed476d..75257e0bce 100644
--- a/lib/dns/rdatavec.c
+++ b/lib/dns/rdatavec.c
@@ -38,18 +38,15 @@
/*
* The memory structure of an rdatavec is as follows:
*
- * header (dns_vecheader_t)
- * record count (2 bytes, big endian)
+ * header (dns_vecheader_t, including record count)
* data records
* data length (2 bytes, big endian)
* meta data (1 byte for RRSIG, 0 bytes for all other types)
* data (data length bytes)
*
- * A "bare" rdatavec is everything after the header. The first two bytes
- * contain the count of rdata records in the rdatavec.
- * After the count, the rdata records are stored sequentially in memory.
- * Each record consists of a length field, optional metadata, and the actual
- * rdata bytes.
+ * A "bare" rdatavec is everything after the header. The data records are
+ * stored sequentially in memory. Each record consists of a length field,
+ * optional metadata, and the actual rdata bytes.
*
* The rdata format depends on the RR type and is defined by the type-specific
* *_fromwire and *_towire functions (e.g., lib/dns/rdata/in_1/a_1.c for A
@@ -95,39 +92,13 @@ compare_rdata(const void *p1, const void *p2) {
return dns_rdata_compare(p1, p2);
}
-static size_t
-header_size(const dns_vecheader_t *header) {
- UNUSED(header);
- return sizeof(dns_vecheader_t);
-}
-
-static unsigned char *
-rdatavec_raw(dns_vecheader_t *header) {
- unsigned char *as_char_star = (unsigned char *)header;
- unsigned char *raw = as_char_star + header_size(header);
-
- return raw;
-}
-
-static unsigned char *
-rdatavec_data(dns_vecheader_t *header) {
- return rdatavec_raw(header) + 2;
-}
-
-static unsigned int
-rdatavec_count(dns_vecheader_t *header) {
- unsigned char *raw = rdatavec_raw(header);
- unsigned int count = get_uint16(raw);
-
- return count;
-}
-
static unsigned char *
newvec(dns_rdataset_t *rdataset, isc_mem_t *mctx, isc_region_t *region,
- size_t size) {
+ size_t size, uint16_t count) {
dns_vecheader_t *header = isc_mem_get(mctx, size);
*header = (dns_vecheader_t){
+ .count = count,
.next_header = ISC_SLINK_INITIALIZER,
.trust = rdataset->trust,
.ttl = rdataset->ttl,
@@ -138,7 +109,7 @@ newvec(dns_rdataset_t *rdataset, isc_mem_t *mctx, isc_region_t *region,
region->base = (unsigned char *)header;
region->length = size;
- return (unsigned char *)header + sizeof(*header);
+ return header->raw;
}
static isc_result_t
@@ -152,7 +123,7 @@ makevec(dns_rdataset_t *rdataset, isc_mem_t *mctx, isc_region_t *region,
dns_rdata_t *rdata = NULL;
unsigned char *rawbuf = NULL;
unsigned int headerlen = sizeof(dns_vecheader_t);
- uint32_t buflen = headerlen + 2;
+ uint32_t buflen = headerlen;
isc_result_t result;
unsigned int nitems;
unsigned int nalloc;
@@ -169,11 +140,10 @@ makevec(dns_rdataset_t *rdataset, isc_mem_t *mctx, isc_region_t *region,
dns_vecheader_t *header = dns_vecheader_getheader(rdataset);
buflen = dns_rdatavec_size(header);
- rawbuf = newvec(rdataset, mctx, region, buflen);
+ rawbuf = newvec(rdataset, mctx, region, buflen, header->count);
INSIST(headerlen <= buflen);
- memmove(rawbuf, (unsigned char *)header + headerlen,
- buflen - headerlen);
+ memmove(rawbuf, header->raw, buflen - headerlen);
return ISC_R_SUCCESS;
}
@@ -186,8 +156,7 @@ makevec(dns_rdataset_t *rdataset, isc_mem_t *mctx, isc_region_t *region,
if (rdataset->type != 0) {
return ISC_R_FAILURE;
}
- rawbuf = newvec(rdataset, mctx, region, buflen);
- put_uint16(rawbuf, 0);
+ (void)newvec(rdataset, mctx, region, buflen, 0);
return ISC_R_SUCCESS;
}
@@ -244,9 +213,8 @@ makevec(dns_rdataset_t *rdataset, isc_mem_t *mctx, isc_region_t *region,
*
* If an rdata is not a duplicate, accumulate the storage size
* required for the rdata. We do not store the class, type, etc,
- * just the rdata, so our overhead is 2 bytes for the number of
- * records, and 2 bytes for the length of each rdata, plus the
- * rdata itself.
+ * just the rdata, so our overhead is 2 bytes for the length of each
+ * rdata, plus the rdata itself.
*/
for (i = 1; i < nalloc; i++) {
if (compare_rdata(&rdata[i - 1], &rdata[i]) == 0) {
@@ -260,7 +228,7 @@ makevec(dns_rdataset_t *rdataset, isc_mem_t *mctx, isc_region_t *region,
if (rdataset->type == dns_rdatatype_rrsig) {
buflen++;
}
- if (buflen - headerlen - 2 > DNS_RDATA_MAXLENGTH) {
+ if (buflen - headerlen > DNS_RDATA_MAXLENGTH) {
result = ISC_R_NOSPACE;
goto free_rdatas;
}
@@ -278,7 +246,7 @@ makevec(dns_rdataset_t *rdataset, isc_mem_t *mctx, isc_region_t *region,
if (rdataset->type == dns_rdatatype_rrsig) {
buflen++;
}
- if (buflen - headerlen - 2 > DNS_RDATA_MAXLENGTH) {
+ if (buflen - headerlen > DNS_RDATA_MAXLENGTH) {
result = ISC_R_NOSPACE;
goto free_rdatas;
}
@@ -299,8 +267,7 @@ makevec(dns_rdataset_t *rdataset, isc_mem_t *mctx, isc_region_t *region,
* Allocate the memory, set up a buffer, start copying in
* data.
*/
- rawbuf = newvec(rdataset, mctx, region, buflen);
- put_uint16(rawbuf, nitems);
+ rawbuf = newvec(rdataset, mctx, region, buflen, nitems);
for (i = 0; i < nalloc; i++) {
if (rdata[i].data == &removed) {
@@ -359,6 +326,7 @@ dns_rdatavec_fromrdataset(dns_rdataset_t *rdataset, isc_mem_t *mctx,
* Reset the vecheader content, but keep the refcount and mctx.
*/
*new = (dns_vecheader_t){
+ .count = new->count,
.next_header = ISC_SLINK_INITIALIZER,
.typepair = DNS_TYPEPAIR_VALUE(rdataset->type,
rdataset->covers),
@@ -376,25 +344,22 @@ unsigned int
dns_rdatavec_size(dns_vecheader_t *header) {
REQUIRE(header != NULL);
- unsigned char *vec = rdatavec_raw(header);
- INSIST(vec != NULL);
-
- unsigned char *current = rdatavec_data(header);
- uint16_t count = rdatavec_count(header);
+ unsigned char *current = header->raw;
+ uint16_t count = header->count;
while (count-- > 0) {
uint16_t length = get_uint16(current);
current += length;
}
- return (unsigned int)(current - vec) + header_size(header);
+ return (unsigned int)(current - (unsigned char *)header);
}
unsigned int
dns_rdatavec_count(dns_vecheader_t *header) {
REQUIRE(header != NULL);
- return rdatavec_count(header);
+ return header->count;
}
static void
@@ -497,18 +462,17 @@ dns_rdatavec_merge(dns_vecheader_t *oheader, dns_vecheader_t *nheader,
isc_mem_t *mctx, dns_rdataclass_t rdclass,
dns_rdatatype_t type, unsigned int flags,
uint32_t maxrrperset, dns_vecheader_t **theaderp) {
- unsigned char *tcurrent = NULL;
unsigned int ocount, ncount, tcount = 0;
unsigned int ndup;
- size_t rlength = 0, tlength = 0;
+ size_t rlength = 0, tlength;
vecmerge_iter_t iter;
dns_rdata_t rdata = DNS_RDATA_INIT;
REQUIRE(theaderp != NULL && *theaderp == NULL);
REQUIRE(oheader != NULL && nheader != NULL);
- ocount = rdatavec_count(oheader);
- ncount = rdatavec_count(nheader);
+ ocount = oheader->count;
+ ncount = nheader->count;
if (maxrrperset > 0 && ocount + ncount > maxrrperset) {
return DNS_R_TOOMANYRECORDS;
@@ -552,22 +516,22 @@ dns_rdatavec_merge(dns_vecheader_t *oheader, dns_vecheader_t *nheader,
return ISC_R_NOSPACE;
}
- tlength = header_size(oheader) + 2 + rlength;
+ tlength = sizeof(*oheader) + rlength;
/*
* Allocate the target buffer and initialize the header.
* Preserve the case of the old header, but the rest from the
* new header.
*/
- unsigned char *tstart = isc_mem_get(mctx, tlength);
- dns_vecheader_t *as_header = (dns_vecheader_t *)tstart;
+ dns_vecheader_t *theader = isc_mem_get(mctx, tlength);
uint16_t attrs = DNS_VECHEADER_GETATTR(
oheader,
DNS_VECHEADERATTR_CASESET | DNS_VECHEADERATTR_CASEFULLYLOWER);
if (RESIGN(nheader)) {
attrs |= DNS_VECHEADERATTR_RESIGN;
}
- *as_header = (dns_vecheader_t){
+ *theader = (dns_vecheader_t){
+ .count = tcount,
.typepair = nheader->typepair,
.mctx = isc_mem_ref(mctx),
.serial = nheader->serial,
@@ -575,15 +539,12 @@ dns_rdatavec_merge(dns_vecheader_t *oheader, dns_vecheader_t *nheader,
.resign = nheader->resign,
.next_header = ISC_SLINK_INITIALIZER,
};
- isc_refcount_init(&as_header->references, 1);
- atomic_init(&as_header->attributes, attrs);
- atomic_init(&as_header->trust, atomic_load_acquire(&nheader->trust));
- memmove(as_header->upper, oheader->upper, sizeof(oheader->upper));
+ isc_refcount_init(&theader->references, 1);
+ atomic_init(&theader->attributes, attrs);
+ atomic_init(&theader->trust, atomic_load_acquire(&nheader->trust));
+ memmove(theader->upper, oheader->upper, sizeof(oheader->upper));
- tcurrent = tstart + header_size(nheader);
-
- /* Write the new count, then start merging the vecs. */
- put_uint16(tcurrent, tcount);
+ unsigned char *tcurrent = theader->raw;
/*
* Now walk the sets together, adding each item in DNSSEC order,
@@ -595,9 +556,9 @@ dns_rdatavec_merge(dns_vecheader_t *oheader, dns_vecheader_t *nheader,
rdata_to_vecitem(&tcurrent, type, &rdata);
}
- INSIST(tcurrent == tstart + tlength);
+ INSIST(tcurrent == (unsigned char *)theader + tlength);
- *theaderp = (dns_vecheader_t *)tstart;
+ *theaderp = theader;
return ISC_R_SUCCESS;
}
@@ -607,7 +568,6 @@ dns_rdatavec_subtract(dns_vecheader_t *oheader, dns_vecheader_t *sheader,
isc_mem_t *mctx, dns_rdataclass_t rdclass,
dns_rdatatype_t type, unsigned int flags,
dns_vecheader_t **theaderp) {
- unsigned char *tcurrent = NULL;
unsigned int ocount, scount;
unsigned int tcount = 0, rcount;
size_t rlength = 0, tlength;
@@ -617,8 +577,8 @@ dns_rdatavec_subtract(dns_vecheader_t *oheader, dns_vecheader_t *sheader,
REQUIRE(theaderp != NULL && *theaderp == NULL);
REQUIRE(oheader != NULL && sheader != NULL);
- ocount = rdatavec_count(oheader);
- scount = rdatavec_count(sheader);
+ ocount = oheader->count;
+ scount = sheader->count;
vecmerge_first(&iter, oheader, sheader, rdclass);
@@ -658,15 +618,15 @@ dns_rdatavec_subtract(dns_vecheader_t *oheader, dns_vecheader_t *sheader,
return DNS_R_UNCHANGED;
}
- tlength = header_size(oheader) + 2 + rlength;
+ tlength = sizeof(*oheader) + rlength;
/*
* Allocate the target buffer and copy the old vec's header.
*/
- unsigned char *tstart = isc_mem_get(mctx, tlength);
- dns_vecheader_t *as_header = (dns_vecheader_t *)tstart;
+ dns_vecheader_t *theader = isc_mem_get(mctx, tlength);
uint16_t attrs = RESIGN(oheader) ? DNS_VECHEADERATTR_RESIGN : 0;
- *as_header = (dns_vecheader_t){
+ *theader = (dns_vecheader_t){
+ .count = tcount,
.typepair = oheader->typepair,
.mctx = isc_mem_ref(mctx),
.serial = oheader->serial,
@@ -674,17 +634,12 @@ dns_rdatavec_subtract(dns_vecheader_t *oheader, dns_vecheader_t *sheader,
.resign = oheader->resign,
.next_header = ISC_SLINK_INITIALIZER,
};
- isc_refcount_init(&as_header->references, 1);
- atomic_init(&as_header->attributes, attrs);
- atomic_init(&as_header->trust, atomic_load_acquire(&oheader->trust));
- memmove(as_header->upper, oheader->upper, sizeof(oheader->upper));
+ isc_refcount_init(&theader->references, 1);
+ atomic_init(&theader->attributes, attrs);
+ atomic_init(&theader->trust, atomic_load_acquire(&oheader->trust));
+ memmove(theader->upper, oheader->upper, sizeof(oheader->upper));
- tcurrent = tstart + header_size(oheader);
-
- /*
- * Write the new count.
- */
- put_uint16(tcurrent, tcount);
+ unsigned char *tcurrent = theader->raw;
/*
* Copy the parts of the old vec that didn't have duplicates.
@@ -695,9 +650,9 @@ dns_rdatavec_subtract(dns_vecheader_t *oheader, dns_vecheader_t *sheader,
rdata_to_vecitem(&tcurrent, type, &rdata);
}
- INSIST(tcurrent == tstart + tlength);
+ INSIST(tcurrent == (unsigned char *)theader + tlength);
- *theaderp = (dns_vecheader_t *)tstart;
+ *theaderp = theader;
return ISC_R_SUCCESS;
}
@@ -727,14 +682,11 @@ dns_vecheader_setownercase(dns_vecheader_t *header, const dns_name_t *name) {
dns_vecheader_t *
dns_vecheader_new(isc_mem_t *mctx) {
- dns_vecheader_t *h = NULL;
-
- h = isc_mem_get(mctx, sizeof(*h) + sizeof(uint16_t));
+ dns_vecheader_t *h = isc_mem_get(mctx, sizeof(*h));
*h = (dns_vecheader_t){
.references = ISC_REFCOUNT_INITIALIZER(1),
.mctx = isc_mem_ref(mctx),
};
- ISC_U16TO8_BE(h->raw, 0);
return h;
}
@@ -743,20 +695,16 @@ dns_vecheader_new(isc_mem_t *mctx) {
isc_result_t
vecheader_first(rdatavec_iter_t *iter, dns_vecheader_t *header,
dns_rdataclass_t rdclass) {
- unsigned char *raw = rdatavec_data(header);
- uint16_t count = rdatavec_count(header);
- if (count == 0) {
- iter->iter_pos = NULL;
- iter->iter_count = 0;
- return ISC_R_NOMORE;
- }
+ uint16_t count = header->count;
- iter->iter_pos = raw;
- iter->iter_count = count;
- iter->iter_rdclass = rdclass;
- iter->iter_type = DNS_TYPEPAIR_TYPE(header->typepair);
+ *iter = (rdatavec_iter_t){
+ .iter_pos = count == 0 ? NULL : header->raw,
+ .iter_count = count,
+ .iter_rdclass = rdclass,
+ .iter_type = DNS_TYPEPAIR_TYPE(header->typepair),
+ };
- return ISC_R_SUCCESS;
+ return count == 0 ? ISC_R_NOMORE : ISC_R_SUCCESS;
}
isc_result_t
@@ -840,7 +788,7 @@ rdataset_clone(const dns_rdataset_t *source,
static unsigned int
rdataset_count(dns_rdataset_t *rdataset) {
- return rdatavec_count(rdataset->vec.header);
+ return rdataset->vec.header->count;
}
static void
diff --git a/lib/dns/rdatavec_p.h b/lib/dns/rdatavec_p.h
index 98a0b8faa6..cd55bd0ac2 100644
--- a/lib/dns/rdatavec_p.h
+++ b/lib/dns/rdatavec_p.h
@@ -17,15 +17,12 @@
#include <dns/rdatavec.h>
-#define peek_uint16(buffer) ISC_U8TO16_BE(buffer)
-
#define CASEFULLYLOWER(header) \
((atomic_load_acquire(&(header)->attributes) & \
DNS_VECHEADERATTR_CASEFULLYLOWER) != 0)
#define CASESET(header) \
((atomic_load_acquire(&(header)->attributes) & \
DNS_VECHEADERATTR_CASESET) != 0)
-#define EXISTS(header) (peek_uint16((header)->raw) != 0)
#define IGNORE(header) \
((atomic_load_acquire(&(header)->attributes) & \
DNS_VECHEADERATTR_IGNORE) != 0)
@@ -36,6 +33,7 @@
((atomic_load_acquire(&(header)->attributes) & \
DNS_VECHEADERATTR_RESIGN) != 0)
+#define peek_uint16(buffer) ISC_U8TO16_BE(buffer)
#define get_uint16(buffer) \
({ \
uint16_t __ret = peek_uint16(buffer); \
diff --git a/tests/dns/vecheader_test.c b/tests/dns/vecheader_test.c
index 44d674d59e..43f459ff44 100644
--- a/tests/dns/vecheader_test.c
+++ b/tests/dns/vecheader_test.c
@@ -114,8 +114,7 @@ ISC_RUN_TEST_IMPL(zero_count_vecheader) {
dns_rdatatype_none);
assert_int_equal(dns_rdatavec_count(empty), 0);
- assert_int_equal(dns_rdatavec_size(empty),
- sizeof(dns_vecheader_t) + sizeof(uint16_t));
+ assert_int_equal(dns_rdatavec_size(empty), sizeof(dns_vecheader_t));
CHECK(create_vecheader(mctx, dns_rdatatype_a, dns_rdataclass_in, 300,
"192.0.2.1", &header));
@@ -174,7 +173,7 @@ ISC_RUN_TEST_IMPL(merge_headers) {
/* Test: merged size should be first_size + second_size - sizeof(header)
* - count_field_size */
- expected_size = size1 + size2 - sizeof(dns_vecheader_t) - 2;
+ expected_size = size1 + size2 - sizeof(dns_vecheader_t);
assert_int_equal(merged_size, expected_size);
/* Test: merged count should be first_count + second_count */