0

I'm having a problem with memory leak, when I use Valgrind it tells me that I have 512bytes of memory leaked, I know the problem is with load because of Valgrind and because my load functions is returning false every time (in debug I can't step into the for loop, so the function step over to return false). Can someone help me with this ? How should I debug it ?

EDIT -> this is the loop inside the load function that both program and debugger are skipping (and the function only returns true inside the loop) :

for (int i = fgetc(dict); i == EOF; i = fgetc(dict)){
    if (i == EOF){
        fclose(dict);
        return true;
    }
    nword[j] = i;

// when a "\" appears (only appears when fallowed by a "n") terminate the word.  
    if (nword[j] == '\\'){
        nword[j] = '\0';
        hash(nword);

    // counts number of words
        new_word++;

    // so then the "n" is used before initiating a new word.
        fgetc(dict);

    // starts a new word.
        j = 0;
    }
    j++;
}

This is the Valgrind log :

==3958== Memcheck, a memory error detector
==3958== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al.
==3958== Using Valgrind-3.13.0 and LibVEX; rerun with -h for copyright info
==3958== Command: ./speller texts/cat.txt
==3958== 
Could not load dictionaries/large.
==3958== 
==3958== HEAP SUMMARY:
==3958==     in use at exit: 552 bytes in 1 blocks
==3958==   total heap usage: 3 allocs, 2 frees, 5,672 bytes allocated
==3958== 
==3958== 552 bytes in 1 blocks are still reachable in loss record 1 of 1
==3958==    at 0x4C2FB0F: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==3958==    by 0x5258EB9: __fopen_internal (iofopen.c:65) 
==3958==    by 0x5258EB9: fopen@@GLIBC_2.2.5 (iofopen.c:89)
==3958==    by 0x40135E: load (dictionary.c:120)
==3958==    by 0x4008B4: main (speller.c:40)
==3958== 
==3958== LEAK SUMMARY:
==3958==    definitely lost: 0 bytes in 0 blocks
==3958==    indirectly lost: 0 bytes in 0 blocks
==3958==      possibly lost: 0 bytes in 0 blocks
==3958==    still reachable: 552 bytes in 1 blocks
==3958==         suppressed: 0 bytes in 0 blocks
==3958== 
==3958== For counts of detected and suppressed errors, rerun with: -v
==3958== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0

And this is some of the code :

node *root = NULL;

int new_word = 0;

node *create_root(node *y)
{
    y = malloc(sizeof(node));
        if (root != NULL)
        {
            y->endOfWord = false;
            for (int i = 0; i < 27; i++)
            {
                y->path[i] = NULL;
            }
        }
    return y;
}
// Hashes word to a number
unsigned int hash(const char *word){
    root = create_root(root);
    node *tmp = root;
    int index;
    for (int j = 0; j < strlen(word); j++){
        if (check_char(&word[j])){
            index = CHAR_TO_INDEX(&word[j]);
            if (word[j] == '\''){
                index = 26;
            }
            if (!tmp->path[index]){
                tmp->path[index] = create_root(tmp);
            }
            tmp = tmp->path[index];
        }
        else
            return 1;
    }
    tmp->endOfWord = true;
    return 0;
}

// Loads dictionary into memory, returning true if successful else false
bool load(const char *dictionary)
{
    FILE *dict = fopen(dictionary, "r");
    if (dict == NULL){
        return false;
    }
    int j = 0;
    char nword[LENGTH];
    for (int i = fgetc(dict); i == EOF; i = fgetc(dict)){
        if (i == EOF){
            fclose(dict);
            return true;
        }
        nword[j] = i;
    
    // when a "\" appears (only appears when fallowed by a "n") terminate the word.  
        if (nword[j] == '\\'){
            nword[j] = '\0';
            hash(nword);
        
        // counts number of words
            new_word++;
        
        // so then the "n" is used before initiating a new word.
            fgetc(dict);
        
        // starts a new word.
            j = 0;
        }
        j++;
    }
    return false;
}

void free_nodes(node *x){
if (!x){
        return;
}

for (int i = 0; i < 26; i++){
    if (x->path[i] != NULL){
        free_nodes(x->path[i]);
    }
    else
        continue;
    }

free(x);
}

// Unloads dictionary from memory, returning true if successful else false
bool unload(void)
{
    // TODO
    free_nodes(root);
    if(!root){
        return true;
    }
    return false;
}
1

Interesting... 1 block, 552 bytes related to an fopen statement in load. What's the size of a file pointer?

Did you remember to close the dictionary file before ending the load function? ;-)

BTW, why does load return false when it completes successfully?

Hint: valgrind might give you some clues about memory leaks in a program, but you should be focused on getting the program running correctly before worrying about valgrind results. Often, software bugs that cause a program to produce incorrect results also cause valgrind issues. Solve the logic and then check for memory leaks.

If this answers your question, please click on the check mark to accept. Let's keep up on forum maintenance. ;-)

  • I don't know why, but the program is jumping this for loop in the load function for (int i = fgetc(dict); i == EOF; i = fgetc(dict)){ if (i == EOF){ fclose(dict); return true; } so I'm closing the file, but it is not getting inside the loop to close it. When I tried to use the debugger from cs50 IDE I wasn't able to step into the loop. I have no idea whats wrong with the loop tho :/ – Eduardo Moraes Nov 24 '20 at 17:24
  • regarding the file size, its 1,37MB but still 552b were not free – Eduardo Moraes Nov 24 '20 at 17:36
  • I fixed the bug, it was in the loop, i had it set to "i == EOF". changing it to "i != eof" fixed it. – Eduardo Moraes Nov 24 '20 at 18:09
  • Glad you figured it out. RE: file size, the 552 bytes isn't the size of the file, it's the size of the file POINTER. – Cliff B Nov 24 '20 at 20:24

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .