Search code examples
cvalgrindfree

Always a memory leak even though I free'd all allocates


I can't seem to find the problem to why there is always a leak with the prio_q_create function. I do free it with prio_q_destroy but valgrind still shows a leak error.

#include <stdlib.h>
#include <stdio.h>

typedef struct prio_q prio_q;
typedef struct elem elem;
struct prio_q {
    int size;           
    struct elem *first; 
};

struct elem {
    void *data;
    int prio;
    struct elem *next;
};

struct prio_q *prio_q_create() {
    prio_q *list = calloc(1, sizeof(prio_q));
    list->first = NULL;
    list->size = 0;
    return list;
}

void prio_q_push(struct prio_q *q, void *data, int prio) {
    elem *e = calloc(1, sizeof(elem));
    e->prio = prio;
    e->data = data;
    e->next = NULL;
    if (q->first == NULL) {
        q->first = e;
        q->size = q->size + 1;
    } else {
        if (q->first->prio < prio) {
            e->next = q->first;
            q->first = e;
            q->size = q->size + 1;
        } else {
            elem *temp = q->first;
            while (temp->next != NULL && temp->next->prio >= prio) {
                temp = temp->next;
            }
            e->next = temp->next;
            temp->next = e;
            q->size = q->size + 1;
        }
    }
}

void *prio_q_pop(struct prio_q *q) {
    if (q->first != NULL) {
        elem *temp = q->first;
        q->first = q->first->next;
        void *data = temp->data;
        temp->next = NULL;
        free(temp);
        return data;
    } else
        exit(0);
}

void *prio_q_front(struct prio_q *q) {
    return q->first->data;
}

void prio_q_destroy(struct prio_q *q) {
    elem *temp = q->first;                 
    elem *next_temp;                           
    while (temp != NULL) {        
        next_temp = temp->next;
        free(temp);
        temp = next_temp;        
    } 
    free(q);
}

int main() {
    struct prio_q *queue;
    char *s;
    int i;

    queue = prio_q_create();

    prio_q_push(queue, "amet...", 2);
    prio_q_push(queue, "ipsum", 7);
    prio_q_push(queue, "dolor", 4);
    prio_q_push(queue, "Lorem", 22);
    prio_q_push(queue, "sit", 3);

    prio_q_push(queue, "Hello World", 1);
    prio_q_push(queue, "Bye World", 0);

    for (i = 0; i < 5; i++) {
        s = prio_q_pop(queue);
        printf("%s\n", s);
    }

    s = prio_q_front(queue);
    printf("%s\n", s);
    prio_q_destroy(queue);
    return 0;
}

Should be the whole code. The main mostly pushes some strings with prio number onto the list and prints them out via a loop. The valgrind error


Solution

  • There is no leak in the posted code. Either you are testing code that is not posted or your version of Valgrind might detect a false positive caused by the C library allocating a buffer for stdout. Try without the printf statements.

    Here is my Valgrind trace:

    chqrlie$ make memleak
    gcc -O2 -funsigned-char -std=c99 -Wall -Wextra -W -Wmissing-field-initializers -lm -o memleak memleak.c
    chqrlie$ valgrind ./memleak
    ==45671== Memcheck, a memory error detector
    ==45671== Copyright (C) 2002-2011, and GNU GPL'd, by Julian Seward et al.
    ==45671== Using Valgrind-3.7.0 and LibVEX; rerun with -h for copyright info
    ==45671== Command: ./memleak
    ==45671==
    amet...
    ipsum
    dolor
    Lorem
    sit
    Hello World
    ==45671==
    ==45671== HEAP SUMMARY:
    ==45671==     in use at exit: 0 bytes in 0 blocks
    ==45671==   total heap usage: 8 allocs, 8 frees, 184 bytes allocated
    ==45671==
    ==45671== All heap blocks were freed -- no leaks are possible
    ==45671==
    ==45671== For counts of detected and suppressed errors, rerun with: -v
    ==45671== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 4 from 4)
    chqrlie$