I was having a pretty productive day finding and fixing those two arcane bugs, I gather :-) I'll commit them right away. Looking into the array bounds problem is critical. Drew had some ideas about the list.c implementation he considered rather obvious. I suppose that's his inner teacher talking, leaving the actual solution to the student....

All I can come up with is adding to list.c:105

tlist->start->nextnode=NULL;

so tlist->start is never without a nextnode field.

This is mandatory. You can't ever not do that. In fact, I consider it best practice to do the following:

struct mystruct *ptr = (struct mystruct *)malloc(sizeof(struct mystruct));
if (ptr != NULL) {
  bzero(ptr, sizeof(struct mystruct));
  /* Set initial/default values here if needed */
  /* ptr->blah = foo; */
}

That way the entire contents of mystruct is zero'ed out in the event that mystruct gets changed and a new member is added. I also wrap all of these kinds of calls in functions so I can do something like:

struct mystruct* ptr = mystruct_new();

and not have to worry about chasing down all instances of malloc(3) to adjust for code that changes.

Or better, fully initialize a struct element * before assigning it to tlist->start.

How about:

struct element *new = (struct element *)my_malloc(sizeof(element));
new->data = (void *)my_malloc(dsize);
new->data = memcpy(new->data,data,dsize);
new->dsize = dsize;
new->nextnode = tlist->start;
tlist->start = new;

I left out the return value checks on the mallocs, for clarity sake.

Using the bzero(3) approach, plus setting the default values is the best way to go.

/* Global context */
struct mystruct *list_ptr = NULL;

/* In a function: */
struct mystruct *ptr = mystruct_new();

/* Initialize ptr w/ the correct values, then call mystruct_prepend() when you're ready to prepend it onto the list. */
mystruct_prepend(&list_ptr, ptr);


void
mystruct_prepend(struct mystruct **list, struct mystruct *elem) {
  struct mystruct *tmp;

  if (list == NULL)
    return;
  else if (*list == NULL)
    *list = elem;
  else {
    elem->next = *list->head;
    *list = elem;
  }
}


How's that? This all being fine and well, I recommend making a copy of and using the macros provided by sys/queue.h instead that way you can get tail appends and never have to worry about uninitialized values or bugs since these routines are well tested and fast (ie, they're used in the kernel).


But I'm still unable to reproduce this bug, which makes it rather difficult to track down.

Send me a patch, I can reproduce this problem in seconds with OS-X's Mail.app. -sc

--
Sean Chittenden

Reply via email to