Hello,

the TAILQ_LAST and TAILQ_PREV macros in sys/queue.h only
work because by coincidence the head and the entry struct are
similar (they both have 2 pointers: struct type* and struct type**).

If you insert a char dummy in between:

#define TAILQ_ENTRY(type)                                \
struct {                                                                \
       struct type *tqe_next;  /* next element */          \
       char dummy; \
       struct type **tqe_prev; /* address of previous next element */  \
}

then the test program below will crash:

pref:afarber> cat tailq.c
/* gcc -DQUEUE_MACRO_DEBUG tailq.c -o tailq */
#include <stdio.h>
#include <sys/queue.h>

typedef struct element {
       TAILQ_ENTRY(element)    field;
       int                     i;
} element;

TAILQ_HEAD(headname, element)   head = TAILQ_HEAD_INITIALIZER(head);

int
main(int argc, char* argv[])
{
       int             i;
       element         *pe;

       for (i = 0; i < 10; i++) {
               if ((pe = (element*) malloc(sizeof(*pe))) == NULL)
                       err(1, NULL);
               pe->i = i;
               TAILQ_INSERT_TAIL(&head, pe, field);
       }

       printf("TAILQ_FOREACH:\n");
       TAILQ_FOREACH(pe, &head, field) {
               printf("%d\n", pe->i);
       }

       printf("TAILQ_FOREACH_REVERSE:\n");
       TAILQ_FOREACH_REVERSE(pe, &head, headname, field) {
               printf("%d\n", pe->i);
       }

       printf("TAILQ_LAST:\n");
       pe = TAILQ_LAST(&head, headname);
       printf("%d\n", pe->i);

       return 0;
}

pref:afarber> gcc -DQUEUE_MACRO_DEBUG tailq.c -o tailq

pref:afarber> ./tailq
TAILQ_FOREACH:
0
1
2
3
4
5
6
7
8
9
TAILQ_FOREACH_REVERSE:
Segmentation fault (core dumped)

Also the TAILQ_LAST macro cheats by taking a (head)->tqh_last
and saying that it's a pointer to the last element. But in fact it's a
pointer to the tqe_next member of the last element. This works only
because that member is the 1st one in that structure.

IMHO a solution would be to change the head structure to hold
just that: the pointer to the last element (which is needed above):

#define TAILQ_HEAD(name, type)                                          \
struct name {                                                           \
       struct type *tqh_first; /* first element */                     \
       struct type *tqh_last; /* addr of last element */         \
}

By fixing those 2 issues the headname argument of the 3 macros
TAILQ_LAST, TAILQ_PREV and TAILQ_FOREACH_REVERSE
could be dropped...

Am I wrong?

Regards
Alex


--
http://preferans.de

Reply via email to