Search code examples
cvalgrindrealloc

Valgrind runs infinitely with realloc but code works


So, I am trying to copy char per char of a file in a chunk of memory that expands accordingly with the file's size... At the end the code print all ok, but if I use valgrind it will run forever.

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


int main(void)
{
    FILE *dict = fopen("dictionaries/large", "r");
    if (dict == NULL)
    {
        printf("Could not load the file\n");
        return 1;
    }

    // Buffer to read data.
    char *buffer = malloc(1);
    if (buffer == NULL)
    {
        return 1;
    }

    char *word = malloc(1);
    if (word == NULL)
    {
        return 1;
    }

    int i = 0;

    // Load file byte per byte. Copy char per char.
    while (fread(buffer, 1, 1, dict))
    {
        word[i] = buffer[0];
        i++;
        char *tmp = realloc(word, i + 1);
        word = tmp;
    }

    printf("%s\n", word);

    fclose(dict);
    free(buffer);
    free(word);
}

Valgrind's report:

I tried to create a temporary pointer after realloc and then assign the new pointer to the old one, but it didn't work as realloc can return a pointer to another address.


Solution

  • It is always easier to divide program into logical bits and place them in functions.

    char *addToBuff(char *buff, int ch, size_t *size)
    {
        //working on local variable buff. No need for a temporary variable
        buff = realloc(buff, *size + 1);
        if(buff)
        {
            buff[*size] = ch;
            *size += 1;
        }
        return buff;
    }
    
    char *readToBuff(FILE *fi, size_t *size)
    {
        char *buff = NULL;
        int ch;
        *size = 0;
        while((ch = fgetc(fi)) != EOF)
        {
            //to avoid memory leak - temporary variable needed
            char *tmp = addToBuff(buff, ch, size);
            if(!tmp) {/* handle allocation error */}
            else buff = tmp;
        }
        return buff;
    }
    
    
    int main(void)
    {
        size_t size = 0;
        char *buff = readToBuff(stdin, &size);
    
        printf("read %zu chars. Buff address: '%p'\n", size, (void*)buff);
        free(buff);
    }
    

    https://godbolt.org/z/n56xsd3Pd