1

This has been driving me crazy. When I run my test program on this doubly linked list it gives me a Segmentation fault when I try and free my list. I know there is a memory leak due to not freeing the allocated memory correctly but no matter what I try it doesn't seem to fix it. Any help as to where I need free the memory to avoid a memory leak and the seg fault would be appreciated

struct list { 

    char *value;
    struct list *next;
    struct list *prev;
};

const char *list_node_value(list_t *node) {

    return node->value;
}

list_t *list_first(list_t *list) {

    return list;
}

list_t *list_last(list_t *list) {

    return list->prev;
}

list_t *list_next(list_t *node) {

    return node->next;
}

list_t *list_previous(list_t *node) {

    return node->prev;

}

static void failed_allocation(void) {

    fprintf(stderr, "Out of memory.\n");
    abort();
}

static list_t *new_node(const char *value) {

    list_t *node = malloc(sizeof(list_t));
    if (!node) failed_allocation();
    node->value = malloc(strlen(value));
    if (!node->value) failed_allocation();
    strcpy(node->value, value);
    return node;
}

list_t *list_insert_before(list_t *list, list_t *node, const char *value) {

    list_t *insert_node = new_node(value);
    insert_node->prev = node->prev;
    insert_node->next = node;
    insert_node->next->prev = insert_node;
    insert_node->prev->next = insert_node;
    if (list == node) {
        return insert_node;
    } else {
        return list;
    }
}

list_t *list_append(list_t *list, const char *value) {

    if (list) {

        (void) list_insert_before(list, list, value);
        return list;
    } else {

        list_t *node = new_node(value);
        node->prev = node->next = node;
        return node;
    }
}

list_t *list_prepend(list_t *list, const char *value) {

    if (list) {

        return list_insert_before(list, list, value);
    } else {

        list_t *node = new_node(value);
        node->prev = node->next = node;
        return node;
    }
}

list_t *list_remove(list_t *list, list_t *node) {

    (node->prev)->next = node->next;
    (node->next)->prev = node->prev;
    if (list != node) {

    return list;
    } else {

        return list->next == list ? NULL : list->next;
    }   
}

void list_free(list_t *list) {

    while (list_remove(list, list_last(list)) != NULL) { }

    }



void list_foreach(list_t *list, void (*function)(const char*)) {

    if (list) {

        list_t *cur = list_first(list);
        do {

            function(cur->value);
            cur = cur->next;
        } while (cur != list_first(list));
    }
}

5 Answers 5

1

Your problem is heap corruption. you have:

   node->value = malloc(strlen(value));

it should be:

   node->value = malloc(strlen(value)+1);
Sign up to request clarification or add additional context in comments.

3 Comments

You beat me by a few seconds.
Sorry I didn't ask the question. :)
@xiaomao sorry, I missed this :)
1
  1. You are not freeing anything at all; disconnecting it from the list doesn't free it.

  2. It's not just a doubly-linked list; it is a circular list.

  3. I don't see code to initialize a list, which may be the source of your problem.

Comments

0

Run your program linked to efence or with valgrind.

This should tell you where memory is lost or pointers dereferenced, etc...

Comments

0
if (!node) failed_allocation();
node->value = malloc(strlen(value));

Problem is you didn't allocate space for the '\0' NUL byte. Try:

if (!node) failed_allocation();
node->value = malloc(strlen(value)+1);

Comments

0

I see at least one defect here:

node->value = malloc(strlen(value));

It shall be strlen(value) + 1 to keep zero terminator char, otherwise next strcpy() call will lead to buffer overrun and can damage heap:

node->value = malloc(strlen(value) + 1);

5 Comments

Why would this cause a problem when FREEING the list?
As mentioned I can see where this would cause problems with the memory but how would I go about freeing the list? if I put a free(node) in the list_remove function I just get a seg fault
@user1691282 Where exactly you put free() call and what cause seg fault after that? free() call ifself? You shall read data from deleted node before freeing it.
@ScottHunter It could cause problems on free() in case when buffer overrun corrupts the heap
@Rost I am putting the free() such that list_t *list_remove(list_t *list, list_t *node) { (node->prev)->next = node->next; (node->next)->prev = node->prev; if (list != node) { free(node); return list; } else { return list->next == list ? NULL : list->next; } } but I am still not freeing all the memory and Im not sure how to fix it

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.