简体   繁体   中英

Why doesn't TAILQ_REMOVE reset the head pointer?

I'm tracking down a few odd Coverity bugs in some code I didn't write. In one case, we use TAILQ_FIRST and TAILQ_REMOVE in a loop, like so:

while (!TAILQ_EMPTY(&queue))
{
    item* entry = TAILQ_FIRST(&queue);
    TAILQ_REMOVE(&queue, entry, next);
    free(entry);
}

Coverity complains a lot about this, saying I'm double-freeing. However, looking at TAILQ_REMOVE, this might be right: ( /usr/include/x86_64-linux-gnu/sys/queue.h on my Linux box)

#define TAILQ_REMOVE(head, elm, field) do {                             \
        if (((elm)->field.tqe_next) != NULL)                            \
                (elm)->field.tqe_next->field.tqe_prev =                 \
                    (elm)->field.tqe_prev;                              \
        else                                                            \
                (head)->tqh_last = (elm)->field.tqe_prev;               \
        *(elm)->field.tqe_prev = (elm)->field.tqe_next;                 \
} while (/*CONSTCOND*/0)

Unlike in some other related macros, I don't see anything here that resets tqe_first if I delete the head node. Thus, I would keep getting the deleted node in my loop.

But I don't really understand what's going on. This code appears to work despite the Coverity warnings.

Finding examples on the net for this is difficult.

This works because tqe_prev is a pointer to a pointer. If non-empty, the first element in the queue has its tqe_prev field initialized to the address of the tqe_first . So, dereferencing it and assigning to it, as it does in the last line of the macro, will end up setting the tqh_first if you are removing the first element. (Normally, tqe_prev would have the address of the tqe_next pointer of the previous node.)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM