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 | }
|
---|