return (leaf);
}
+ /*
+ * Special case: if the search key differs even before the root
+ * key offset, it means the name desired either precedes or
+ * follows the entire range of names in the database, and
+ * popping up the stack won't help us, so just move the
+ * iterator one step back from the origin and return.
+ */
+ if (to < branch_key_offset(iter->stack[0])) {
+ dns_qpiter_init(qp, iter);
+ return (prevleaf(iter));
+ }
/*
* As long as the branch offset point is after the point where the
* search key differs, we need to branch up and find a better leaf
* go to the parent branch and iterate back to the
* predecessor from that point.
*/
- iter->stack[iter->sp] = NULL;
- iter->sp--;
n = prevleaf(iter);
leaf = n;
} else {
dns_qp_destroy(&qp);
}
+/*
+ * this is a regression test for an infinite loop that could
+ * previously occur in fix_iterator()
+ */
+ISC_RUN_TEST_IMPL(fixiterator) {
+ dns_qp_t *qp = NULL;
+ const char insert[][32] = { "dynamic.",
+ "a.dynamic.",
+ "aaaa.dynamic.",
+ "cdnskey.dynamic.",
+ "cds.dynamic.",
+ "cname.dynamic.",
+ "dname.dynamic.",
+ "dnskey.dynamic.",
+ "ds.dynamic.",
+ "mx.dynamic.",
+ "ns.dynamic.",
+ "nsec.dynamic.",
+ "private-cdnskey.dynamic.",
+ "private-dnskey.dynamic.",
+ "rrsig.dynamic.",
+ "txt.dynamic.",
+ "" };
+ int i = 0;
+
+ dns_qp_create(mctx, &string_methods, NULL, &qp);
+ while (insert[i][0] != '\0') {
+ insert_str(qp, insert[i++]);
+ }
+
+ static struct check_predecessors check1[] = {
+ { "newtext.dynamic.", "mx.dynamic.", DNS_R_PARTIALMATCH, 6 },
+ { "absent.", "txt.dynamic.", ISC_R_NOTFOUND, 0 },
+ { "nonexistent.", "txt.dynamic.", ISC_R_NOTFOUND, 0 },
+ { NULL, NULL, 0, 0 }
+ };
+
+ check_predecessors(qp, check1);
+
+ dns_qp_destroy(&qp);
+}
+
ISC_TEST_LIST_START
ISC_TEST_ENTRY(qpkey_name)
ISC_TEST_ENTRY(qpkey_sort)
ISC_TEST_ENTRY(partialmatch)
ISC_TEST_ENTRY(qpchain)
ISC_TEST_ENTRY(predecessors)
+ISC_TEST_ENTRY(fixiterator)
ISC_TEST_LIST_END
ISC_TEST_MAIN