/* There is a right way and a wrong way to remove the last element of a tailq. The right way does it in two steps. This fact is undocumented anywhere and never asked on SO. When the TAILQ_REMOVE is in an intermediate state of removal, it proceeds with a subsequent step starting from its "remove this guy" argument. So "remove this guy" must be fully evaluated to a concrete node (call by value). If you try to do it with nested expressions, this subsequent call of "from which guy again?" performs an evaluation of TAILQ_LAST in the intermediate state (call by name), which gives the wrong value. Everything then gets trashed. The actual/expected annotations are for the symptom that led me to the test. actual means without -DFIXIT expected obtains with -DFIXIT Other outputs are unannotated, but we can easily see things getting trashed in them too. */ #include #include #ifdef FIXIT #define MY_TAILQ_REMOVE_LAST(headp, TYPE, HEADNAME, NAME) ({\ struct TYPE * last = TAILQ_LAST(headp, HEADNAME); \ TAILQ_REMOVE(headp, last, NAME); \ }) #else #define MY_TAILQ_REMOVE_LAST(headp, TYPE, HEADNAME, NAME) \ TAILQ_REMOVE(headp, TAILQ_LAST(headp, HEADNAME), NAME) #endif int main () { struct req { int pri, rqr; TAILQ_ENTRY(req) x; }; TAILQ_HEAD(reql, req); struct reql reqs = TAILQ_HEAD_INITIALIZER(reqs); TAILQ_INIT(&reqs); struct req r1 = {1, 42}, r2 = {2, 42}; struct req *cur; /* (Irrelevant to the bug, not a problem:) You can't navigate next/prev for unlisted elements (it crashes). So I only show them for listed ones. */ printf("r1@%p, r2@%p\n", &r1, &r2); printf("reqs.first = %p\n", TAILQ_FIRST(&reqs)); printf("reqs.last = %p\n", TAILQ_LAST(&reqs, reql)); printf("reqs ="); TAILQ_FOREACH(cur, &reqs, x) printf(" %p", cur); printf("\n"); TAILQ_INSERT_TAIL(&reqs, &r1, x); printf("-\n"); printf("r1.next=%p\n", TAILQ_NEXT(&r1, x)); // a&e: (nil) is last printf("r1.prev=%p\n", TAILQ_PREV(&r1, reql, x)); // a&e: (nil) is first printf("reqs.first = %p\n", TAILQ_FIRST(&reqs)); printf("reqs.last = %p\n", TAILQ_LAST(&reqs, reql)); printf("reqs ="); TAILQ_FOREACH(cur, &reqs, x) printf(" %p", cur); printf("\n"); TAILQ_INSERT_TAIL(&reqs, &r2, x); printf("-\n"); printf("r1.next=%p\n", TAILQ_NEXT(&r1, x)); // a&e: @r2 has succ printf("r1.prev=%p\n", TAILQ_PREV(&r1, reql, x)); // a&e: (nil) is first printf("r2.next=%p\n", TAILQ_NEXT(&r2, x)); // a&e: (nil) is last printf("r2.prev=%p\n", TAILQ_PREV(&r2, reql, x)); // a&e: @r1 has pred printf("reqs.first = %p\n", TAILQ_FIRST(&reqs)); printf("reqs.last = %p\n", TAILQ_LAST(&reqs, reql)); printf("reqs ="); TAILQ_FOREACH(cur, &reqs, x) printf(" %p", cur); printf("\n"); MY_TAILQ_REMOVE_LAST(&reqs, req, reql, x); printf("-\n"); printf("r1.next=%p\n", TAILQ_NEXT(&r1, x)); // e: (nil) is last; a: @r2 printf("r1.prev=%p\n", TAILQ_PREV(&r1, reql, x)); // e: (nil) is first; a: @r2 printf("reqs.first = %p\n", TAILQ_FIRST(&reqs)); printf("reqs.last = %p\n", TAILQ_LAST(&reqs, reql)); printf("reqs ="); TAILQ_FOREACH(cur, &reqs, x) printf(" %p", cur); printf("\n"); MY_TAILQ_REMOVE_LAST(&reqs, req, reql, x); printf("-\n"); printf("reqs.first = %p\n", TAILQ_FIRST(&reqs)); printf("reqs.last = %p\n", TAILQ_LAST(&reqs, reql)); printf("reqs ="); // e: (none); a: @ TAILQ_FOREACH(cur, &reqs, x) printf(" %p", cur); printf("\n"); }