2

I have a function which prints the whole content of the file and the function seems to work fine, but valgring complains about Conditional jump or move depends on uninitialised value(s) and Uninitialised value was created by a heap allocation:

==7876== Memcheck, a memory error detector
==7876== Copyright (C) 2002-2013, and GNU GPL'd, by Julian Seward et al.
==7876== Using Valgrind-3.10.1 and LibVEX; rerun with -h for copyright info
==7876== Command: ./program
==7876== 
==7876== Conditional jump or move depends on uninitialised value(s)
==7876==    at 0x4E864B2: vfprintf (vfprintf.c:1642)
==7876==    by 0x4E8CC38: printf (printf.c:33)
==7876==    by 0x40074C: main (program.c:45)
==7876==  Uninitialised value was created by a heap allocation
==7876==    at 0x4C2BBA0: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==7876==    by 0x4008A7: printFile (program.c:23)
==7876==    by 0x40073A: main (program.c:43)
==7876== 
The world is not enought and michi is the only one who's not agree.
==7876== 
==7876== HEAP SUMMARY:
==7876==     in use at exit: 0 bytes in 0 blocks
==7876==   total heap usage: 2 allocs, 2 frees, 621 bytes allocated
==7876== 
==7876== All heap blocks were freed -- no leaks are possible
==7876== 
==7876== For counts of detected and suppressed errors, rerun with: -v
==7876== ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 0 from 0)

Here is the program:

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

char *printFile(char *fileName){
    size_t length=0,size=0;
    char *buffer;
    FILE *file;

    file = fopen (fileName , "r" );

    if (file==NULL){
        printf("\n");
        printf("\tThe file %s does not Exists\n", fileName);
        exit(1);
    }

    fseek (file , 0 , SEEK_END);
    length = (size_t)ftell (file);
    fseek (file , 0 , SEEK_SET);


    buffer = malloc(length+1);

    if (!buffer){
        fputs ("Memory error",stderr);
        exit (2);
    }

    size = fread (buffer,1,length+1,file);

    if (size != length){
        fputs ("Reading error",stderr);
        exit(3);
    }

    fclose (file);
    return buffer;
}

int main (void) {
    char *fileName = "test.txt";
    char *fileContent = printFile(fileName);

    printf("%s",fileContent);
    free(fileContent);
    return 0;
}

A quick fix is to use calloc instead of malloc, because it zeros the returned bytes So I replaced:

buffer = malloc(length+1);

with:

buffer = calloc(length,sizeof(char*));

And valgrind doesn't complain:

==7897== Memcheck, a memory error detector
==7897== Copyright (C) 2002-2013, and GNU GPL'd, by Julian Seward et al.
==7897== Using Valgrind-3.10.1 and LibVEX; rerun with -h for copyright info
==7897== Command: ./program
==7897== 
The world is not enought and michi is the only one who's not agree.
==7897== 
==7897== HEAP SUMMARY:
==7897==     in use at exit: 0 bytes in 0 blocks
==7897==   total heap usage: 2 allocs, 2 frees, 1,096 bytes allocated
==7897== 
==7897== All heap blocks were freed -- no leaks are possible
==7897== 
==7897== For counts of detected and suppressed errors, rerun with: -v
==7897== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)

My question is, why does malloc produce that error and how to avoid calloc. Do I have some codding problem here or is just malloc? . . EDIT: if I change:

size = fread (buffer,1,length+1,file);

with:

size = fread (buffer,1,length,file);

I get:

==7985== Memcheck, a memory error detector
==7985== Copyright (C) 2002-2013, and GNU GPL'd, by Julian Seward et al.
==7985== Using Valgrind-3.10.1 and LibVEX; rerun with -h for copyright info
==7985== Command: ./program
==7985== 
==7985== Invalid read of size 1
==7985==    at 0x4E864B2: vfprintf (vfprintf.c:1642)
==7985==    by 0x4E8CC38: printf (printf.c:33)
==7985==    by 0x40074C: main (program.c:44)
==7985==  Address 0x52022f4 is 0 bytes after a block of size 68 alloc'd
==7985==    at 0x4C2BBA0: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==7985==    by 0x4008A6: printFile (program.c:22)
==7985==    by 0x40073A: main (program.c:42)
==7985== 
The world is not enought and michi is the only one who's not agree.
==7985== 
==7985== HEAP SUMMARY:
==7985==     in use at exit: 0 bytes in 0 blocks
==7985==   total heap usage: 2 allocs, 2 frees, 620 bytes allocated
==7985== 
==7985== All heap blocks were freed -- no leaks are possible
==7985== 
==7985== For counts of detected and suppressed errors, rerun with: -v
==7985== ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 0 from 0)
Michi
  • 5,175
  • 7
  • 33
  • 58
  • 1
    `size = fread (buffer,1,length+1,file);` -->> `size = fread (buffer,1,length,file);` And you should nul-terminate the buffer: `buffer[length] = 0;` There is also a limt to what printf() can print as a single string: `printf("%s",fileContent);` – wildplasser Oct 15 '15 at 18:36
  • I did tried that too, is not from there. – Michi Oct 15 '15 at 18:37
  • 1
    You allocated room for the `nul` string terminator, but forgot to write `'\0'` to the end of the array holding the file content. – Weather Vane Oct 15 '15 at 18:38
  • 1
    Memory obtained via `malloc()` is uninitialized. That's intentional. The workarounds are to use `calloc()` instead or to initialize that memory obtained via `malloc()` before you read from it. Under some circumstances you can initialize only part of it, and often you have better initial values available than all zeroes. – John Bollinger Oct 15 '15 at 18:39
  • @JohnBollinger If I understand, do I have to use calloc here ? – Michi Oct 15 '15 at 18:41
  • 1
    Re your edit, it should be `size = fread (buffer,1,length,file);` and not `size = fread (buffer,1,length+1,file);` since the file only contains `length` bytes. – Weather Vane Oct 15 '15 at 18:42
  • No! OP wants to ensure at least a NUL char at the end, so `file length + 1`. – Jean-Baptiste Yunès Oct 15 '15 at 18:44
  • @Jean-BaptisteYunès Yes – Michi Oct 15 '15 at 18:45
  • @Jean-BaptisteYunès so where does the `nul` magically come from? There are `length` bytes in the file and that is all. Telling it to read `length+1` bytes won't change anything. – Weather Vane Oct 15 '15 at 18:45
  • This is why it works with calloc... file length + 1 bytes zero-allocated and file length filled from the file, so NUL terminated. – Jean-Baptiste Yunès Oct 15 '15 at 18:46
  • working with length+1 and adding **'\0'** to the buffer created that problem. I'm so angry on myself. – Michi Oct 15 '15 at 18:55

3 Answers3

2

You print the file content read into your buffer but nothing can ensure that the buffer contains a NUL char, so valgrind complains because printf parse your data until NUL (jump or move depends on uninitialised value(s)). Using calloc tells valgrind that you are more precautious...

Jean-Baptiste Yunès
  • 34,548
  • 4
  • 48
  • 69
1

Memory obtained via malloc() is uninitialized. That's intentional. The workarounds are to use calloc() instead or to initialize that memory obtained via malloc() before you read from it. Under some circumstances you can initialize only part of it, and often you have better initial values available than all zeroes.

Your particular error is only peripherally related to that, however. You do initialize most of the buffer, via fread(), but you allocate one more byte than the file is long, and fread() does not store anything in that last byte. It looks like maybe you intended to add a '\0' terminator, but forgot. It's that last byte that valgrind complains about.

In this case, the memory-clearing performed by calloc() mostly serves no purpose, as you are about to overwrite all bytes in the buffer but one. But it does initialize that last byte, too, which turns out to save you several kinds of trouble when you fail to initialize it any other way.

John Bollinger
  • 160,171
  • 8
  • 81
  • 157
  • It doesn't complains specifically about the last, but because `printf` parse that area and nothing ensures that a NUL byte will be encountered. – Jean-Baptiste Yunès Oct 15 '15 at 18:48
  • 1
    @Jean-BaptisteYunès, valgrind is complaining about a jump or move in `vprintf()` that depends on an uninitialized value. The only uninitialized value in sight is the byte at the end of the buffer. If the buffer were being overrun then valgrind would have a different complaint. – John Bollinger Oct 15 '15 at 18:51
1

Your string must be NUL-terminated. Without it, the program has undefined behaviour, which valgrind rightfully reports.

The easiest way to NUL-terminate the string is:

size = fread (buffer,1,length,file); /* no need to specify useless extra char */
                                     /* it will never be read */
...                                  /* check for errors here */
buffer[length] = '\0';               /* <--- null termination */

calloc fills the entire buffer with NUL characters, but it's a waste of cycles. You only need one.

n. m. could be an AI
  • 112,515
  • 14
  • 128
  • 243
  • I'm sorry, it was just a fast type. It works now, but i didn't realized that **length + 1** and adding that **'\0'** is the same. It is ok now and works. – Michi Oct 15 '15 at 18:52