mirror of
https://gitlab.isc.org/isc-projects/bind9
synced 2025-08-31 22:45:39 +00:00
Decouple database and node lifetimes by adding node-specific vtables
All databases in the codebase follow the same structure: a database is an associative container from DNS names to nodes, and each node is an associative container from RR types to RR data. Each database implementation (qpzone, qpcache, sdlz, builtin, dyndb) has its own corresponding node type (qpznode, qpcnode, etc). However, some code needs to work with nodes generically regardless of their specific type - for example, to acquire locks, manage references, or register/unregister slabs from the heap. Currently, these generic node operations are implemented as methods in the database vtable, which creates problematic coupling between database and node lifetimes. If a node outlives its parent database, the node destructor will destroy all RR data, and each RR data destructor will try to unregister from heaps by calling a virtual function from the database vtable. Since the database was already freed, this causes a crash. This commit breaks the coupling by standardizing the layout of all database nodes, adding a dedicated vtable for node operations, and moving node-specific methods from the database vtable to the node vtable.
This commit is contained in:
@@ -105,11 +105,11 @@ struct dns_sdlz_db {
|
||||
|
||||
struct dns_sdlzlookup {
|
||||
/* Unlocked */
|
||||
unsigned int magic;
|
||||
DBNODE_FIELDS;
|
||||
|
||||
dns_sdlz_db_t *sdlz;
|
||||
ISC_LIST(dns_rdatalist_t) lists;
|
||||
ISC_LIST(isc_buffer_t) buffers;
|
||||
dns_name_t name;
|
||||
ISC_LINK(dns_sdlzlookup_t) link;
|
||||
dns_rdatacallbacks_t callbacks;
|
||||
|
||||
@@ -187,8 +187,18 @@ static void
|
||||
list_tordataset(dns_rdatalist_t *rdatalist, dns_db_t *db, dns_dbnode_t *node,
|
||||
dns_rdataset_t *rdataset);
|
||||
|
||||
/*
|
||||
* Node methods forward declarations
|
||||
*/
|
||||
static void
|
||||
detachnode(dns_db_t *db, dns_dbnode_t **targetp DNS__DB_FLARG);
|
||||
sdlznode_attachnode(dns_dbnode_t *source, dns_dbnode_t **targetp DNS__DB_FLARG);
|
||||
static void
|
||||
sdlznode_detachnode(dns_dbnode_t **targetp DNS__DB_FLARG);
|
||||
|
||||
static dns_dbnode_methods_t sdlznode_methods = (dns_dbnode_methods_t){
|
||||
.attachnode = sdlznode_attachnode,
|
||||
.detachnode = sdlznode_detachnode,
|
||||
};
|
||||
|
||||
static void
|
||||
dbiterator_destroy(dns_dbiterator_t **iteratorp DNS__DB_FLARG);
|
||||
@@ -248,8 +258,7 @@ static void
|
||||
rdatasetiter_destroy(dns_rdatasetiter_t **iteratorp DNS__DB_FLARG) {
|
||||
sdlz_rdatasetiter_t *sdlziterator = (sdlz_rdatasetiter_t *)(*iteratorp);
|
||||
|
||||
detachnode(sdlziterator->common.db,
|
||||
&sdlziterator->common.node DNS__DB_FLARG_PASS);
|
||||
sdlznode_detachnode(&sdlziterator->common.node DNS__DB_FLARG_PASS);
|
||||
isc_mem_put(sdlziterator->common.db->mctx, sdlziterator,
|
||||
sizeof(sdlz_rdatasetiter_t));
|
||||
*iteratorp = NULL;
|
||||
@@ -396,6 +405,7 @@ createnode(dns_sdlz_db_t *sdlz, dns_sdlznode_t **nodep) {
|
||||
|
||||
node = isc_mem_get(sdlz->common.mctx, sizeof(dns_sdlznode_t));
|
||||
|
||||
node->methods = &sdlznode_methods;
|
||||
node->sdlz = NULL;
|
||||
dns_db_attach((dns_db_t *)sdlz, (dns_db_t **)&node->sdlz);
|
||||
ISC_LIST_INIT(node->lists);
|
||||
@@ -622,16 +632,11 @@ findnode(dns_db_t *db, const dns_name_t *name, bool create,
|
||||
}
|
||||
|
||||
static void
|
||||
attachnode(dns_db_t *db, dns_dbnode_t *source,
|
||||
dns_dbnode_t **targetp DNS__DB_FLARG) {
|
||||
dns_sdlz_db_t *sdlz = (dns_sdlz_db_t *)db;
|
||||
sdlznode_attachnode(dns_dbnode_t *source,
|
||||
dns_dbnode_t **targetp DNS__DB_FLARG) {
|
||||
dns_sdlznode_t *node = (dns_sdlznode_t *)source;
|
||||
uint_fast32_t refs;
|
||||
|
||||
REQUIRE(VALID_SDLZDB(sdlz));
|
||||
|
||||
UNUSED(sdlz);
|
||||
|
||||
refs = isc_refcount_increment(&node->references);
|
||||
#if DNS_DB_NODETRACE
|
||||
fprintf(stderr, "incr:node:%s:%s:%u:%p->references = %" PRIuFAST32 "\n",
|
||||
@@ -644,16 +649,12 @@ attachnode(dns_db_t *db, dns_dbnode_t *source,
|
||||
}
|
||||
|
||||
static void
|
||||
detachnode(dns_db_t *db, dns_dbnode_t **targetp DNS__DB_FLARG) {
|
||||
dns_sdlz_db_t *sdlz = (dns_sdlz_db_t *)db;
|
||||
sdlznode_detachnode(dns_dbnode_t **targetp DNS__DB_FLARG) {
|
||||
dns_sdlznode_t *node;
|
||||
uint_fast32_t refs;
|
||||
|
||||
REQUIRE(VALID_SDLZDB(sdlz));
|
||||
REQUIRE(targetp != NULL && *targetp != NULL);
|
||||
|
||||
UNUSED(sdlz);
|
||||
|
||||
node = (dns_sdlznode_t *)(*targetp);
|
||||
*targetp = NULL;
|
||||
|
||||
@@ -878,7 +879,7 @@ findext(dns_db_t *db, const dns_name_t *name, dns_dbversion_t *version,
|
||||
* and try again.
|
||||
*/
|
||||
if (i < nlabels) {
|
||||
detachnode(db, &node DNS__DB_FLARG_PASS);
|
||||
sdlznode_detachnode(&node DNS__DB_FLARG_PASS);
|
||||
node = NULL;
|
||||
continue;
|
||||
}
|
||||
@@ -928,7 +929,7 @@ findext(dns_db_t *db, const dns_name_t *name, dns_dbversion_t *version,
|
||||
if (nodep != NULL) {
|
||||
*nodep = node;
|
||||
} else if (node != NULL) {
|
||||
detachnode(db, &node DNS__DB_FLARG_PASS);
|
||||
sdlznode_detachnode(&node DNS__DB_FLARG_PASS);
|
||||
}
|
||||
|
||||
return result;
|
||||
@@ -964,7 +965,8 @@ allrdatasets(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version,
|
||||
iterator->common.methods = &rdatasetiter_methods;
|
||||
iterator->common.db = db;
|
||||
iterator->common.node = NULL;
|
||||
attachnode(db, node, &iterator->common.node DNS__DB_FLARG_PASS);
|
||||
sdlznode_attachnode((dns_dbnode_t *)node,
|
||||
&iterator->common.node DNS__DB_FLARG_PASS);
|
||||
iterator->common.version = version;
|
||||
iterator->common.options = options;
|
||||
iterator->common.now = now;
|
||||
@@ -1157,8 +1159,6 @@ static dns_dbmethods_t sdlzdb_methods = {
|
||||
.closeversion = closeversion,
|
||||
.findnode = findnode,
|
||||
.find = find,
|
||||
.attachnode = attachnode,
|
||||
.detachnode = detachnode,
|
||||
.createiterator = createiterator,
|
||||
.findrdataset = findrdataset,
|
||||
.allrdatasets = allrdatasets,
|
||||
@@ -1265,8 +1265,8 @@ dbiterator_current(dns_dbiterator_t *iterator, dns_dbnode_t **nodep,
|
||||
dns_name_t *name DNS__DB_FLARG) {
|
||||
sdlz_dbiterator_t *sdlziter = (sdlz_dbiterator_t *)iterator;
|
||||
|
||||
attachnode(iterator->db, (dns_dbnode_t *)sdlziter->current,
|
||||
nodep DNS__DB_FLARG_PASS);
|
||||
sdlznode_attachnode((dns_dbnode_t *)sdlziter->current,
|
||||
nodep DNS__DB_FLARG_PASS);
|
||||
if (name != NULL) {
|
||||
dns_name_copy(&sdlziter->current->name, name);
|
||||
return ISC_R_SUCCESS;
|
||||
@@ -1295,21 +1295,16 @@ dbiterator_origin(dns_dbiterator_t *iterator, dns_name_t *name) {
|
||||
static void
|
||||
disassociate(dns_rdataset_t *rdataset DNS__DB_FLARG) {
|
||||
dns_dbnode_t *node = rdataset->rdlist.node;
|
||||
dns_sdlznode_t *sdlznode = (dns_sdlznode_t *)node;
|
||||
dns_db_t *db = (dns_db_t *)sdlznode->sdlz;
|
||||
|
||||
detachnode(db, &node DNS__DB_FLARG_PASS);
|
||||
sdlznode_detachnode(&node DNS__DB_FLARG_PASS);
|
||||
dns_rdatalist_disassociate(rdataset DNS__DB_FLARG_PASS);
|
||||
}
|
||||
|
||||
static void
|
||||
rdataset_clone(dns_rdataset_t *source, dns_rdataset_t *target DNS__DB_FLARG) {
|
||||
dns_dbnode_t *node = source->rdlist.node;
|
||||
dns_sdlznode_t *sdlznode = (dns_sdlznode_t *)node;
|
||||
dns_db_t *db = (dns_db_t *)sdlznode->sdlz;
|
||||
|
||||
dns_rdatalist_clone(source, target DNS__DB_FLARG_PASS);
|
||||
attachnode(db, node, &target->rdlist.node DNS__DB_FLARG_PASS);
|
||||
sdlznode_attachnode(node, &target->rdlist.node DNS__DB_FLARG_PASS);
|
||||
}
|
||||
|
||||
static dns_rdatasetmethods_t rdataset_methods = {
|
||||
@@ -1324,8 +1319,8 @@ static dns_rdatasetmethods_t rdataset_methods = {
|
||||
};
|
||||
|
||||
static void
|
||||
list_tordataset(dns_rdatalist_t *rdatalist, dns_db_t *db, dns_dbnode_t *node,
|
||||
dns_rdataset_t *rdataset) {
|
||||
list_tordataset(dns_rdatalist_t *rdatalist, dns_db_t *db ISC_ATTR_UNUSED,
|
||||
dns_dbnode_t *node, dns_rdataset_t *rdataset) {
|
||||
/*
|
||||
* The sdlz rdataset is an rdatalist, but additionally holds
|
||||
* a database node reference.
|
||||
@@ -1333,7 +1328,7 @@ list_tordataset(dns_rdatalist_t *rdatalist, dns_db_t *db, dns_dbnode_t *node,
|
||||
|
||||
dns_rdatalist_tordataset(rdatalist, rdataset);
|
||||
rdataset->methods = &rdataset_methods;
|
||||
dns_db_attachnode(db, node, &rdataset->rdlist.node);
|
||||
dns_db_attachnode(node, &rdataset->rdlist.node);
|
||||
}
|
||||
|
||||
/*
|
||||
|
Reference in New Issue
Block a user