Search code examples
cunixvalgrindrealloc

Valgrind jump or move depends on uninitialised value(s) using getline and one char *


I am trying to use getline and a char pointer to store all results of getline to that one pointer:


    char *final = NULL;
    char *line = NULL;
    size_t n = 0;
    ssize_t result;
    int current_size = 0;
    while ((result = getline(&line, &n, in)) != -1){
        current_size += result;
        final = realloc(final, current_size ); //valgrind error
        if (final== NULL)
            return NULL;
        strcat(final,line);
    }


But I always get the error:

==695== Conditional jump or move depends on uninitialised value(s)
==695==    at 0x483B6D0: malloc (in /usr/lib/x86_64-linux-gnu/valgrind/vgpreload_memcheck-amd64-linux.so)
==695==    by 0x483E017: realloc (in /usr/lib/x86_64-linux-gnu/valgrind/vgpreload_memcheck-amd64-linux.so)
... method trace

I know, that realloc just allocates, not initalises values, but if I try to memset in the next line, valgrind tells me:

==695== Conditional jump or move depends on uninitialised value(s)
==695==    at 0x48428EC: memset (in /usr/lib/x86_64-linux-gnu/valgrind/vgpreload_memcheck-amd64-linux.so)
... method trace

I read a lot of SO contributions, but could not manage to fix that problem with the solutions shown in those. I am sure that that's not the worst memory-leak, but it's still one, so I am trying to fix it. Has anyone an idea how to fix that?


Solution

  • You are close, but your use of current_size += result; before the call to realloc() prevents a simple check of current_size == 0 to check for the first iteration which you would then want to initialize final as an empty-string.

    You can do the following:

    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    
    int main (void) {
    
        char *final = NULL, *line = NULL;
        size_t n = 0, current_size = 0;
        ssize_t result;
        
        while ((result = getline(&line, &n, stdin)) != -1) {
            if (result > 0)
                line[--result] = 0;                                 /* trim \n */
            
            final = realloc (final, current_size + result + 1);     /* add room for \0 */
            if (final== NULL)                                       /* validate allocation */
                return 1;
            
            if (!current_size)                                      /* if 1st word */
                *final = 0;                                         /* make final empty-str */
            
            current_size += result;                                 /* now update value */
            strcat (final, line);                                   /* concatenate */
        }
        
        printf ("%zu - %s\n", current_size, final);
        
        free (final);
        free (line);
    }
    

    Example Use/Output

    $ ./bin/getlineplusone << 'eof'
    1234
    56
    789
    eof
    9 - 123456789
    

    Memory Use/Error Check

    $ valgrind ./bin/getlineplusone << 'eof'
    1234
    56
    789
    eof
    ==8438== Memcheck, a memory error detector
    ==8438== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al.
    ==8438== Using Valgrind-3.13.0 and LibVEX; rerun with -h for copyright info
    ==8438== Command: ./bin/getlineplusone
    ==8438==
    9 - 123456789
    ==8438==
    ==8438== HEAP SUMMARY:
    ==8438==     in use at exit: 0 bytes in 0 blocks
    ==8438==   total heap usage: 6 allocs, 6 frees, 5,262 bytes allocated
    ==8438==
    ==8438== All heap blocks were freed -- no leaks are possible
    ==8438==
    ==8438== For counts of detected and suppressed errors, rerun with: -v
    ==8438== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)