简体   繁体   中英

malloc doesn't look to work in my program

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) 

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...

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.

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.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM