From: Mark Andrews Date: Mon, 16 Dec 2013 22:08:59 +0000 (+1100) Subject: 3692. [bug] Two calls to dns_db_getoriginnode were fatal if there X-Git-Tag: v9.6-ESV-R11rc1~15 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=3a2ea636103eaf40404fb82f228605d384c36434;p=thirdparty%2Fbind9.git 3692. [bug] Two calls to dns_db_getoriginnode were fatal if there was no data at the node. [RT #35080] (cherry picked from commit 161e803a5608956271d8120be37a1b383d14b647) --- diff --git a/CHANGES b/CHANGES index 19d448b5f03..62637c25aef 100644 --- a/CHANGES +++ b/CHANGES @@ -1,3 +1,6 @@ +3692. [bug] Two calls to dns_db_getoriginnode were fatal if there + was no data at the node. [RT #35080] + --- 9.6-ESV-R11b1 released --- 3679. [bug] dig could fail to clean up TCP sockets still diff --git a/lib/dns/rbtdb.c b/lib/dns/rbtdb.c index 2dd4aa077d9..941b77e92db 100644 --- a/lib/dns/rbtdb.c +++ b/lib/dns/rbtdb.c @@ -1638,8 +1638,11 @@ decrement_reference(dns_rbtdb_t *rbtdb, dns_rbtnode_t *node, nodelock = &rbtdb->node_locks[bucket]; +#define KEEP_NODE(n, r) \ + ((n)->data != NULL || (n)->down != NULL || (n) == (r)->origin_node) + /* Handle easy and typical case first. */ - if (!node->dirty && (node->data != NULL || node->down != NULL)) { + if (!node->dirty && KEEP_NODE(node, rbtdb)) { dns_rbtnode_refdecrement(node, &nrefs); INSIST((int)nrefs >= 0); if (nrefs == 0) { @@ -1708,12 +1711,11 @@ decrement_reference(dns_rbtdb_t *rbtdb, dns_rbtnode_t *node, isc_refcount_decrement(&nodelock->references, &refs); INSIST((int)refs >= 0); - /* - * XXXDCL should this only be done for cache zones? - */ - if (node->data != NULL || node->down != NULL) + if (KEEP_NODE(node, rbtdb)) goto restore_locks; +#undef KEEP_NODE + if (write_locked) { /* * We can now delete the node. diff --git a/lib/dns/tests/Makefile.in b/lib/dns/tests/Makefile.in index 50a53cfd1b0..7f57b892769 100644 --- a/lib/dns/tests/Makefile.in +++ b/lib/dns/tests/Makefile.in @@ -38,12 +38,13 @@ LIBS = @LIBS@ @ATFLIBS@ OBJS = dnstest.@O@ SRCS = dnstest.c master_test.c time_test.c dbiterator_test.c \ - dbversion_test.c zonemgr_test.c nsec3_test.c rdata_test.c + dbversion_test.c zonemgr_test.c nsec3_test.c rdata_test.c \ + db_test.c SUBDIRS = TARGETS = master_test@EXEEXT@ time_test@EXEEXT@ dbiterator_test@EXEEXT@ \ dbversion_test@EXEEXT@ zonemgr_test@EXEEXT@ nsec3_test@EXEEXT@ \ - rdata_test@EXEEXT@ + rdata_test@EXEEXT@ db_test@EXEEXT@ @BIND9_MAKE_RULES@ @@ -81,6 +82,11 @@ rdata_test@EXEEXT@: rdata_test.@O@ ${ISCDEPLIBS} ${DNSDEPLIBS} ${LIBTOOL_MODE_LINK} ${PURIFY} ${CC} ${CFLAGS} ${LDFLAGS} -o $@ \ rdata_test.@O@ ${DNSLIBS} ${ISCLIBS} ${LIBS} +db_test@EXEEXT@: db_test.@O@ ${ISCDEPLIBS} ${DNSDEPLIBS} + ${LIBTOOL_MODE_LINK} ${PURIFY} ${CC} ${CFLAGS} ${LDFLAGS} -o $@ \ + db_test.@O@ ${DNSLIBS} \ + ${ISCLIBS} ${LIBS} + unit:: sh ${top_srcdir}/unit/unittest.sh diff --git a/lib/dns/tests/db_test.c b/lib/dns/tests/db_test.c new file mode 100644 index 00000000000..f31c0ab0e7d --- /dev/null +++ b/lib/dns/tests/db_test.c @@ -0,0 +1,86 @@ +/* + * Copyright (C) 2011, 2012 Internet Systems Consortium, Inc. ("ISC") + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH + * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, + * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM + * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE + * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/* $Id$ */ + +/*! \file */ + +#include + +#include + +#include +#include + +#include +#include +#include +#include + +#include "dnstest.h" + +/* + * Helper functions + */ + +#define BUFLEN 255 +#define BIGBUFLEN (64 * 1024) +#define TEST_ORIGIN "test" + +/* + * Individual unit tests + */ + +ATF_TC(getoriginnode); +ATF_TC_HEAD(getoriginnode, tc) { + atf_tc_set_md_var(tc, "descr", + "test multiple calls to dns_db_getoriginnode"); +} +ATF_TC_BODY(getoriginnode, tc) { + dns_db_t *db = NULL; + dns_dbnode_t *node = NULL; + isc_mem_t *mctx = NULL; + isc_result_t result; + + result = isc_mem_create(0, 0, &mctx); + ATF_REQUIRE_EQ(result, ISC_R_SUCCESS); + + result = isc_hash_create(mctx, NULL, 256); + ATF_REQUIRE_EQ(result, ISC_R_SUCCESS); + + result = dns_db_create(mctx, "rbt", dns_rootname, dns_dbtype_zone, + dns_rdataclass_in, 0, NULL, &db); + ATF_REQUIRE_EQ(result, ISC_R_SUCCESS); + + result = dns_db_getoriginnode(db, &node); + ATF_REQUIRE_EQ(result, ISC_R_SUCCESS); + dns_db_detachnode(db, &node); + + result = dns_db_getoriginnode(db, &node); + ATF_REQUIRE_EQ(result, ISC_R_SUCCESS); + dns_db_detachnode(db, &node); + + dns_db_detach(&db); + isc_mem_detach(&mctx); +} + +/* + * Main + */ +ATF_TP_ADD_TCS(tp) { + ATF_TP_ADD_TC(tp, getoriginnode); + return (atf_no_error()); +}