1 | /* |
---|
2 | |
---|
3 | There is a right way and a wrong way to remove the last element of a tailq. |
---|
4 | The right way does it in two steps. |
---|
5 | This fact is undocumented anywhere and never asked on SO. |
---|
6 | |
---|
7 | When the TAILQ_REMOVE is in an intermediate state of removal, it proceeds with a subsequent step starting from its "remove this guy" argument. |
---|
8 | So "remove this guy" must be fully evaluated to a concrete node (call by value). |
---|
9 | 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. |
---|
10 | Everything then gets trashed. |
---|
11 | |
---|
12 | The actual/expected annotations are for the symptom that led me to the test. |
---|
13 | actual means without -DFIXIT |
---|
14 | expected obtains with -DFIXIT |
---|
15 | Other outputs are unannotated, but we can easily see things getting trashed in them too. |
---|
16 | |
---|
17 | */ |
---|
18 | |
---|
19 | |
---|
20 | #include <sys/queue.h> |
---|
21 | #include <stdio.h> |
---|
22 | |
---|
23 | #ifdef FIXIT |
---|
24 | #define MY_TAILQ_REMOVE_LAST(headp, TYPE, HEADNAME, NAME) ({\ |
---|
25 | struct TYPE * last = TAILQ_LAST(headp, HEADNAME); \ |
---|
26 | TAILQ_REMOVE(headp, last, NAME); \ |
---|
27 | }) |
---|
28 | #else |
---|
29 | #define MY_TAILQ_REMOVE_LAST(headp, TYPE, HEADNAME, NAME) \ |
---|
30 | TAILQ_REMOVE(headp, TAILQ_LAST(headp, HEADNAME), NAME) |
---|
31 | #endif |
---|
32 | |
---|
33 | int main () { |
---|
34 | |
---|
35 | struct req { |
---|
36 | int pri, rqr; |
---|
37 | TAILQ_ENTRY(req) x; |
---|
38 | }; |
---|
39 | |
---|
40 | TAILQ_HEAD(reql, req); |
---|
41 | |
---|
42 | struct reql reqs = TAILQ_HEAD_INITIALIZER(reqs); |
---|
43 | TAILQ_INIT(&reqs); |
---|
44 | |
---|
45 | struct req |
---|
46 | r1 = {1, 42}, |
---|
47 | r2 = {2, 42}; |
---|
48 | |
---|
49 | struct req *cur; |
---|
50 | /* |
---|
51 | (Irrelevant to the bug, not a problem:) |
---|
52 | You can't navigate next/prev for unlisted elements (it crashes). |
---|
53 | So I only show them for listed ones. |
---|
54 | */ |
---|
55 | |
---|
56 | printf("r1@%p, r2@%p\n", &r1, &r2); |
---|
57 | |
---|
58 | printf("reqs.first = %p\n", TAILQ_FIRST(&reqs)); |
---|
59 | printf("reqs.last = %p\n", TAILQ_LAST(&reqs, reql)); |
---|
60 | printf("reqs ="); |
---|
61 | TAILQ_FOREACH(cur, &reqs, x) |
---|
62 | printf(" %p", cur); |
---|
63 | printf("\n"); |
---|
64 | |
---|
65 | |
---|
66 | TAILQ_INSERT_TAIL(&reqs, &r1, x); |
---|
67 | |
---|
68 | printf("-\n"); |
---|
69 | printf("r1.next=%p\n", TAILQ_NEXT(&r1, x)); // a&e: (nil) is last |
---|
70 | printf("r1.prev=%p\n", TAILQ_PREV(&r1, reql, x)); // a&e: (nil) is first |
---|
71 | |
---|
72 | printf("reqs.first = %p\n", TAILQ_FIRST(&reqs)); |
---|
73 | printf("reqs.last = %p\n", TAILQ_LAST(&reqs, reql)); |
---|
74 | printf("reqs ="); |
---|
75 | TAILQ_FOREACH(cur, &reqs, x) |
---|
76 | printf(" %p", cur); |
---|
77 | printf("\n"); |
---|
78 | |
---|
79 | TAILQ_INSERT_TAIL(&reqs, &r2, x); |
---|
80 | |
---|
81 | printf("-\n"); |
---|
82 | printf("r1.next=%p\n", TAILQ_NEXT(&r1, x)); // a&e: @r2 has succ |
---|
83 | printf("r1.prev=%p\n", TAILQ_PREV(&r1, reql, x)); // a&e: (nil) is first |
---|
84 | printf("r2.next=%p\n", TAILQ_NEXT(&r2, x)); // a&e: (nil) is last |
---|
85 | printf("r2.prev=%p\n", TAILQ_PREV(&r2, reql, x)); // a&e: @r1 has pred |
---|
86 | |
---|
87 | printf("reqs.first = %p\n", TAILQ_FIRST(&reqs)); |
---|
88 | printf("reqs.last = %p\n", TAILQ_LAST(&reqs, reql)); |
---|
89 | printf("reqs ="); |
---|
90 | TAILQ_FOREACH(cur, &reqs, x) |
---|
91 | printf(" %p", cur); |
---|
92 | printf("\n"); |
---|
93 | |
---|
94 | MY_TAILQ_REMOVE_LAST(&reqs, req, reql, x); |
---|
95 | |
---|
96 | printf("-\n"); |
---|
97 | printf("r1.next=%p\n", TAILQ_NEXT(&r1, x)); // e: (nil) is last; a: @r2 |
---|
98 | printf("r1.prev=%p\n", TAILQ_PREV(&r1, reql, x)); // e: (nil) is first; a: @r2 |
---|
99 | |
---|
100 | printf("reqs.first = %p\n", TAILQ_FIRST(&reqs)); |
---|
101 | printf("reqs.last = %p\n", TAILQ_LAST(&reqs, reql)); |
---|
102 | printf("reqs ="); |
---|
103 | TAILQ_FOREACH(cur, &reqs, x) |
---|
104 | printf(" %p", cur); |
---|
105 | printf("\n"); |
---|
106 | |
---|
107 | MY_TAILQ_REMOVE_LAST(&reqs, req, reql, x); |
---|
108 | |
---|
109 | printf("-\n"); |
---|
110 | |
---|
111 | printf("reqs.first = %p\n", TAILQ_FIRST(&reqs)); |
---|
112 | printf("reqs.last = %p\n", TAILQ_LAST(&reqs, reql)); |
---|
113 | printf("reqs ="); // e: (none); a: @ |
---|
114 | TAILQ_FOREACH(cur, &reqs, x) |
---|
115 | printf(" %p", cur); |
---|
116 | printf("\n"); |
---|
117 | |
---|
118 | } |
---|