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.