diff options
author | emaste <emaste@FreeBSD.org> | 2010-02-20 01:05:30 +0000 |
---|---|---|
committer | emaste <emaste@FreeBSD.org> | 2010-02-20 01:05:30 +0000 |
commit | 1739980e918430b64d94ecba54b8b4b4a817da3d (patch) | |
tree | a61742654c793b96798a121d4702a6f4610bc668 | |
parent | 30767ce70baeb3b458edf7df558973143c661bc5 (diff) | |
download | FreeBSD-src-1739980e918430b64d94ecba54b8b4b4a817da3d.zip FreeBSD-src-1739980e918430b64d94ecba54b8b4b4a817da3d.tar.gz |
Avoid corrupting the list or queue if _REMOVE is invoked with a
reference to the head.
PR: kern/119307
MFC After: 1 week
-rw-r--r-- | sys/sys/queue.h | 20 |
1 files changed, 14 insertions, 6 deletions
diff --git a/sys/sys/queue.h b/sys/sys/queue.h index f1f35c8..257679b 100644 --- a/sys/sys/queue.h +++ b/sys/sys/queue.h @@ -112,6 +112,7 @@ struct qm_trace { #define TRACEBUF struct qm_trace trace; #define TRASHIT(x) do {(x) = (void *)-1;} while (0) +#define QMD_SAVELINK(name, link) void **name = (void *)&(link) #define QMD_TRACE_HEAD(head) do { \ (head)->trace.prevline = (head)->trace.lastline; \ @@ -130,6 +131,7 @@ struct qm_trace { #else #define QMD_TRACE_ELEM(elem) #define QMD_TRACE_HEAD(head) +#define QMD_SAVELINK(name, link) #define TRACEBUF #define TRASHIT(x) #endif /* QUEUE_MACRO_DEBUG */ @@ -189,6 +191,7 @@ struct { \ #define SLIST_NEXT(elm, field) ((elm)->field.sle_next) #define SLIST_REMOVE(head, elm, type, field) do { \ + QMD_SAVELINK(oldnext, (elm)->field.sle_next); \ if (SLIST_FIRST((head)) == (elm)) { \ SLIST_REMOVE_HEAD((head), field); \ } \ @@ -198,7 +201,7 @@ struct { \ curelm = SLIST_NEXT(curelm, field); \ SLIST_REMOVE_AFTER(curelm, field); \ } \ - TRASHIT((elm)->field.sle_next); \ + TRASHIT(*oldnext); \ } while (0) #define SLIST_REMOVE_AFTER(elm, field) do { \ @@ -285,6 +288,7 @@ struct { \ #define STAILQ_NEXT(elm, field) ((elm)->field.stqe_next) #define STAILQ_REMOVE(head, elm, type, field) do { \ + QMD_SAVELINK(oldnext, (elm)->field.stqe_next); \ if (STAILQ_FIRST((head)) == (elm)) { \ STAILQ_REMOVE_HEAD((head), field); \ } \ @@ -294,7 +298,7 @@ struct { \ curelm = STAILQ_NEXT(curelm, field); \ STAILQ_REMOVE_AFTER(head, curelm, field); \ } \ - TRASHIT((elm)->field.stqe_next); \ + TRASHIT(*oldnext); \ } while (0) #define STAILQ_REMOVE_HEAD(head, field) do { \ @@ -415,14 +419,16 @@ struct { \ #define LIST_NEXT(elm, field) ((elm)->field.le_next) #define LIST_REMOVE(elm, field) do { \ + QMD_SAVELINK(oldnext, (elm)->field.le_next); \ + QMD_SAVELINK(oldprev, (elm)->field.le_prev); \ 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); \ + TRASHIT(*oldnext); \ + TRASHIT(*oldprev); \ } while (0) #define LIST_SWAP(head1, head2, type, field) do { \ @@ -587,6 +593,8 @@ struct { \ (*(((struct headname *)((elm)->field.tqe_prev))->tqh_last)) #define TAILQ_REMOVE(head, elm, field) do { \ + QMD_SAVELINK(oldnext, (elm)->field.tqe_next); \ + QMD_SAVELINK(oldprev, (elm)->field.tqe_prev); \ QMD_TAILQ_CHECK_NEXT(elm, field); \ QMD_TAILQ_CHECK_PREV(elm, field); \ if ((TAILQ_NEXT((elm), field)) != NULL) \ @@ -597,8 +605,8 @@ struct { \ QMD_TRACE_HEAD(head); \ } \ *(elm)->field.tqe_prev = TAILQ_NEXT((elm), field); \ - TRASHIT((elm)->field.tqe_next); \ - TRASHIT((elm)->field.tqe_prev); \ + TRASHIT(*oldnext); \ + TRASHIT(*oldprev); \ QMD_TRACE_ELEM(&(elm)->field); \ } while (0) |