Re: [gmime-devel] g_mime_header_list_clear leaving a list in limbo



Hi Jeff,
Hi Ludo,

Can you write a small test case for the g_mime_header_iter_remove() bug that you are seeing?


I'm using gmime from freepascal but the routine is straightforward ;)

procedure TMime.testlistbug;
var
  headers: PGMimeHeaderList;
  iter: GMimeHeaderIter;
  res: gboolean;
begin
  headers:=g_mime_header_list_new;
  g_mime_header_list_set(headers,'A','1');
  g_mime_header_list_set(headers,'B','2');
  // print out
  g_mime_header_list_get_iter(headers,@iter);
  if g_mime_header_iter_first(@iter) then
writeln('First1: ',g_mime_header_iter_get_name(@iter)+': '+g_mime_header_iter_get_value(@iter));
  if g_mime_header_iter_last(@iter) then
writeln('Last1 : ',g_mime_header_iter_get_name(@iter)+': '+g_mime_header_iter_get_value(@iter));
  //delete all
  g_mime_header_iter_first(@iter);
  while g_mime_header_iter_remove(@iter) do ;
  if g_mime_header_iter_first(@iter) then
writeln('First2: ',g_mime_header_iter_get_name(@iter)+': '+g_mime_header_iter_get_value(@iter));
  if g_mime_header_iter_last(@iter) then
writeln('Last2 : ',g_mime_header_iter_get_name(@iter)+': '+g_mime_header_iter_get_value(@iter));
end;

Just adding 2 headers to a new header_list and printing first and last. Then remove all with g_mime_header_iter_remove until false. g_mime_header_iter_first returns false (correct) on the empty list but g_mime_header_iter_last(@iter) returns true and garbage is printed.

g_mime_header_iter_last does a

    last = (GMimeHeader *) iter->hdrlist->list.tailpred;
    if (!last->next)
        return FALSE;

what is tailpred->next pointing to?


I've got a Linux VM set up at the office that I can try to debug on while I try to figure out what is
wrong with my desktop at home.

There's no need to check/update tailpred in list_unlink() because of the way the linked list is designed (using aliases). Of course, it requires gcc -fno-strict-aliasing to be used since
gcc 4.4 or so.

At some point I should re-work list.c to not require -fno-strict-aliasing (I've been working on other areas where I use similar aliasing tricks), but as long as -fno-strict-aliasing continues to work,
I am not in a huge rush.

For example, check this out:

typedef struct _ListNode {
    struct _ListNode *next;
    int id;
} ListNode;

ListNode *list, *tail, *node;
int i;

list = NULL;
tail = (ListNode *) &list;

for (i = 0; i < 10; i++) {
    node = malloc (sizeof (ListNode));
    node->id = i;

    tail->next = node;
    tail = node;
}

tail->next = NULL;

Do you see the simplicity there? It's beautiful! No need to check if tail is NULL in the first iteration of the loop because assigning to tail->next will assign to list (only works because
ListNode.next is the first member of the struct).

This is how list.c works as well, except that it's a doubly-linked list.

Jeff

Thanks. The example is clear. The extension to double linked lists is less obvious though.

Ludo



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]