Index: kern/tty_subr.c =================================================================== RCS file: /home/ncvs/src/sys/kern/tty_subr.c,v retrieving revision 1.34 diff -u -r1.34 tty_subr.c --- kern/tty_subr.c 2001/03/27 10:21:26 1.34 +++ kern/tty_subr.c 2001/04/23 21:49:07 @@ -114,6 +114,9 @@ cblock_free(cblockp) struct cblock *cblockp; { + + KASSERT(((unsigned long)cblockp & (CBLOCK-1)) == 0, + ("Unaligned cblock in cblock_free")); if (isset(cblockp->c_quote, CBQSIZE * NBBY - 1)) bzero(cblockp->c_quote, sizeof cblockp->c_quote); cblockp->c_next = cfreelist; @@ -138,6 +141,8 @@ "cblock_alloc_cblocks: M_NOWAIT malloc failed, trying M_WAITOK\n"); cbp = malloc(sizeof *cbp, M_TTYS, M_WAITOK); } + KASSERT(((unsigned long)cbp & (CBLOCK-1)) == 0, + ("Unaligned cblock alloced in cblock_alloc_cblocks")); /* * Freed cblocks have zero quotes and garbage elsewhere. * Set the may-have-quote bit to force zeroing the quotes. @@ -262,6 +267,134 @@ return (chr); } +#ifdef INVARIANT_SUPPORT +/* + * Verify the clist invariant. Will panic if passed an invalid clist. + * Intended for debugging of tty-drivers. + */ +void clist_invariant(struct clist *, const char *); + +void +clist_invariant( + struct clist *clistp, /* clist to verify */ + const char *descr /* Section of program causing panic */ +) { + struct cblock *cblockp; /* Presently examined cblock */ + struct cblock *cblockp2; /* Loop limit cblock */ + int real_cc; /* real character count */ + int max_loop; /* Number of cblocks to check (max) */ + + if (descr == NULL) + descr = "undescribed"; + + if (clistp == NULL) + panic("clist invariant: NULL clist in %s", descr); + + /* Check for negative counts */ + if (clistp->c_cc < 0) + panic("clist invariant: negative character count(%d) in %s", + clistp->c_cc, descr); + if (clistp->c_cbcount < 0) + panic("clist invariant: negative block count (%d) in %s", + clistp->c_cbcount, descr); + if (clistp->c_cbmax < 0) + panic("clist invariant: negative max block count (%d) in %s", + clistp->c_cbmax, descr); + if (clistp->c_cbreserved < 0) + panic( +"clist invariant: negative reserved block count (%d) in %s", + clistp->c_cbreserved, descr); + + /* Check for generally invalid counts */ + if (clistp->c_cc && + roundup(clistp->c_cc, CBSIZE) / CBSIZE > clistp->c_cbcount) + panic( +"clist invariant: too few cblocks for c_cc (%d vs %d) in %s", + clistp->c_cbcount, clistp->c_cc, descr); + if (roundup(clistp->c_cc, CBSIZE) / CBSIZE + 2 < clistp->c_cbcount) + panic( +"clist invariant: too many cblocks for c_cc (%d vs %d) in %s", + clistp->c_cbcount, clistp->c_cc, descr); + if (clistp->c_cbcount > clistp->c_cbmax) + panic( +"clist invariant: more cblocks than cb_max (%d vs %d) in %s", + clistp->c_cbcount, clistp->c_cbmax, descr); + + if (clistp->c_cc == 0) { + if (clistp->c_cf && clistp->c_cl && + clistp->c_cf != clistp->c_cl) + panic( +"clist invariant: cf (%p) and cl (%p) differ for empty clist in %s", + clistp->c_cf, clistp->c_cl, descr); + return; + } + if (clistp->c_cf == NULL) + panic("clist invariant: cf is NULL with c_cc=%d (cl=%p) in %s", + clistp->c_cc, clistp->c_cl, descr); + if (clistp->c_cl == NULL) + panic("clist invariant: cl is NULL with c_cc=%d (cf=%p) in %s", + clistp->c_cc, clistp->c_cf, descr); + + /* + * Traverse clist to find actual character count and verify that the + * last pointer exists. + */ + cblockp = (struct cblock *)((unsigned long)clistp->c_cf & ~CROUND); + real_cc = (char *)cblockp->c_info - clistp->c_cf; + if (real_cc > 0) + panic( +"clist invariant: cf (%p) points outside c_info block in %s", + clistp->c_cf, descr); + + /* Limit looping */ + max_loop = clistp->c_cbcount*2 + 2; + cblockp2 = cblockp; + + while (cblockp) { + if ((void *)clistp->c_cl > (void *)cblockp && + (char *)clistp->c_cl <= (char *)cblockp + CBLOCK) { + + /* + * We've found the last block in the list - + * handle character count and other checks. + */ + if (clistp->c_cl < (char *)cblockp->c_info) + panic( +"clist invariant: cl (%p) points outside c_info block in %s", + clistp->c_cl, descr); + real_cc += clistp->c_cl - (char *)cblockp->c_info; + if (real_cc != clistp->c_cc) + panic( +"clist invariant: real cc (%d) does not match c_cc (%d) in %s", + real_cc, clistp->c_cc, descr); + if (cblockp->c_next) + panic( +"clist invariant: non-NULL c_next (%p) on last cblock in %s", + cblockp->c_next, descr); + /* Invariant OK */ + return; + } + + /* Increase character count */ + real_cc += CBSIZE; + if (max_loop-- <= 0) { + panic("clist invariant: too long "); + } + cblockp = cblockp->c_next; + if (cblockp == cblockp2) + panic("clist invariant: loop in clist (%p) in %s", + clistp, descr); + if ((max_loop & 1) == 0) { + cblockp2 = cblockp2->c_next; + } + if (cblockp == cblockp2) + panic("clist invariant: loop in clist (%p) in %s", + clistp, descr); + } + panic("clist invariant: terminated before finding c_cl"); +} +#endif + /* * Copy 'amount' of chars, beginning at head of clist 'clistp' to * destination linear buffer 'dest'. Return number of characters @@ -279,8 +412,12 @@ int numc; int s; + KASSERT(dest != NULL, ("destination is NULL in q_to_b")); s = spltty(); +#ifdef INVARIANTS + clist_invariant(clistp, "q_to_b"); +#endif while (clistp && amount && (clistp->c_cc > 0)) { cblockp = (struct cblock *)((intptr_t)clistp->c_cf & ~CROUND); cblockn = cblockp + 1; /* pointer arithmetic! */ @@ -437,6 +574,7 @@ int startbit, endbit, num_between, numc; int s; + KASSERT(src != NULL, ("clist b_to_q on NULL block")); /* * Avoid allocating an initial cblock and then not using it. * c_cc == 0 must imply c_cbount == 0. @@ -446,6 +584,9 @@ s = spltty(); +#ifdef INVARIANTS + clist_invariant(clistp, "b_to_q"); +#endif /* * If there are no cblocks assigned to this clist yet, * then get one. Index: kern/uipc_mbuf.c =================================================================== RCS file: /home/ncvs/src/sys/kern/uipc_mbuf.c,v retrieving revision 1.76 diff -u -r1.76 uipc_mbuf.c --- kern/uipc_mbuf.c 2001/05/23 20:44:54 1.76 +++ kern/uipc_mbuf.c 2001/05/30 14:57:52 @@ -172,6 +172,41 @@ panic("mbinit: failed to initialize mbuf subsystem!"); } +#ifdef INVARIANT_SUPPORT +/* + * Verify that the list of free mbufs is valid - will panic if pointers + * are incorrect (outside mapped memory) or there are loops in the list. + */ +void mbuf_freelist_invariant(void); + +void +mbuf_freelist_invariant() +{ + union mcluster *m; /* Free-list walker */ + union mcluster *m2; /* Free-list walker (loop detector) */ + + mtx_lock(&mbuf_mtx); + m2 = m = mclfree.m_head; + /* + * Loop over all free pages - likely to page-fault if free-list is + * invalid. + */ + while (m) { + m = m->mcl_next; + if (m == NULL) + break; + if (m == m2) + panic("loop in free mbuf list (%p)", m); + m = m->mcl_next; + if (m == m2) + panic("loop in free mbuf list (%p)", m); + m2 = m2->mcl_next; + } + mtx_unlock(&mbuf_mtx); +} +#endif + + /* * Allocate at least nmb reference count structs and place them * on the ref cnt free list.