diff options
author | Ed Maste <emaste@FreeBSD.org> | 2005-11-18 19:41:55 +0000 |
---|---|---|
committer | Ed Maste <emaste@FreeBSD.org> | 2005-11-18 19:41:55 +0000 |
commit | 054ff3bee0a5d28c2cf0866af3d8167335a1fb4e (patch) | |
tree | 70ffc9286f1b85e1efbab4a5dc25d2235777e5d1 /sys/sys/queue.h | |
parent | 24a1c2e842171293b4180e1fd62daf82f050852f (diff) | |
download | src-054ff3bee0a5d28c2cf0866af3d8167335a1fb4e.tar.gz src-054ff3bee0a5d28c2cf0866af3d8167335a1fb4e.zip |
Add sanity checking for QUEUE(3) lists under INVARIANTS. Races may lead
to list corruption, which can be difficult to unravel in a post-mortem
analysis. These checks verify that prev and next pointers are consistent
when inserting or removing elements, thus catching any corruption earlier.
Also use TRASHIT to break LIST and SLIST link pointers on element removal,
from mlaier via -hackers.
Reviewed by: mlaier
Approved by: rwatson (mentor)
Notes
Notes:
svn path=/head/; revision=152590
Diffstat (limited to 'sys/sys/queue.h')
-rw-r--r-- | sys/sys/queue.h | 37 |
1 files changed, 35 insertions, 2 deletions
diff --git a/sys/sys/queue.h b/sys/sys/queue.h index d3f4d6103e76..7caccea05864 100644 --- a/sys/sys/queue.h +++ b/sys/sys/queue.h @@ -100,8 +100,7 @@ * _REMOVE + + + + * */ -#define QUEUE_MACRO_DEBUG 0 -#if QUEUE_MACRO_DEBUG +#ifdef QUEUE_MACRO_DEBUG /* Store the last 2 places the queue element or head was altered */ struct qm_trace { char * lastfile; @@ -199,6 +198,7 @@ struct { \ SLIST_NEXT(curelm, field) = \ SLIST_NEXT(SLIST_NEXT(curelm, field), field); \ } \ + TRASHIT((elm)->field.sle_next); \ } while (0) #define SLIST_REMOVE_HEAD(head, field) do { \ @@ -291,6 +291,7 @@ struct { \ STAILQ_NEXT(STAILQ_NEXT(curelm, field), field)) == NULL)\ (head)->stqh_last = &STAILQ_NEXT((curelm), field);\ } \ + TRASHIT((elm)->field.stqe_next); \ } while (0) #define STAILQ_REMOVE_HEAD(head, field) do { \ @@ -325,6 +326,31 @@ struct { \ * List functions. */ +#if defined(INVARIANTS) || defined(QUEUE_MACRO_DEBUG) +#define QMD_LIST_CHECK_HEAD(head, field) do { \ + if (LIST_FIRST((head)) != NULL && \ + LIST_FIRST((head))->field.le_prev != \ + &LIST_FIRST((head))) \ + panic("Bad list head %p first->prev != head", (head)); \ +} while (0) + +#define QMD_LIST_CHECK_NEXT(elm, field) do { \ + if (LIST_NEXT((elm), field) != NULL && \ + LIST_NEXT((elm), field)->field.le_prev != \ + &((elm)->field.le_next)) \ + panic("Bad link elm %p next->prev != elm", (elm)); \ +} while (0) + +#define QMD_LIST_CHECK_PREV(elm, field) do { \ + if (*(elm)->field.le_prev != (elm)) \ + panic("Bad link elm %p prev->next != elm", (elm)); \ +} while (0) +#else +#define QMD_LIST_CHECK_HEAD(head, field) +#define QMD_LIST_CHECK_NEXT(elm, field) +#define QMD_LIST_CHECK_PREV(elm, field) +#endif /* defined(INVARIANTS) || defined(QUEUE_MACRO_DEBUG) */ + #define LIST_EMPTY(head) ((head)->lh_first == NULL) #define LIST_FIRST(head) ((head)->lh_first) @@ -344,6 +370,7 @@ struct { \ } while (0) #define LIST_INSERT_AFTER(listelm, elm, field) do { \ + QMD_LIST_CHECK_NEXT(listelm, field); \ if ((LIST_NEXT((elm), field) = LIST_NEXT((listelm), field)) != NULL)\ LIST_NEXT((listelm), field)->field.le_prev = \ &LIST_NEXT((elm), field); \ @@ -352,6 +379,7 @@ struct { \ } while (0) #define LIST_INSERT_BEFORE(listelm, elm, field) do { \ + QMD_LIST_CHECK_PREV(listelm, field); \ (elm)->field.le_prev = (listelm)->field.le_prev; \ LIST_NEXT((elm), field) = (listelm); \ *(listelm)->field.le_prev = (elm); \ @@ -359,6 +387,7 @@ struct { \ } while (0) #define LIST_INSERT_HEAD(head, elm, field) do { \ + QMD_LIST_CHECK_HEAD((head), field); \ if ((LIST_NEXT((elm), field) = LIST_FIRST((head))) != NULL) \ LIST_FIRST((head))->field.le_prev = &LIST_NEXT((elm), field);\ LIST_FIRST((head)) = (elm); \ @@ -368,10 +397,14 @@ struct { \ #define LIST_NEXT(elm, field) ((elm)->field.le_next) #define LIST_REMOVE(elm, field) do { \ + QMD_LIST_CHECK_NEXT(elm, field); \ + QMD_LIST_CHECK_PREV(elm, field); \ if (LIST_NEXT((elm), field) != NULL) \ LIST_NEXT((elm), field)->field.le_prev = \ (elm)->field.le_prev; \ *(elm)->field.le_prev = LIST_NEXT((elm), field); \ + TRASHIT((elm)->field.le_next); \ + TRASHIT((elm)->field.le_prev); \ } while (0) /* |