简体   繁体   中英

Valgrind reports memory leak on freed pointer after getline from stdin

Having this code:

#include <stdlib.h>
#include <stdio.h>
void main()
{   
    char *line = calloc(1024, 1);
    size_t size = 0;
    getline(&line, &size, stdin);
    free(line);
}

Valgrind complains:

==5931== HEAP SUMMARY:
==5931==     in use at exit: 1,024 bytes in 1 blocks
==5931==   total heap usage: 3 allocs, 2 frees, 2,168 bytes allocated
==5931== 
==5931== 1,024 bytes in 1 blocks are definitely lost in loss record 1 of 1
==5931==    at 0x4837B65: calloc (vg_replace_malloc.c:752)
==5931==    by 0x10916B: main (test.c:5)
==5931== 
==5931== LEAK SUMMARY:
==5931==    definitely lost: 1,024 bytes in 1 blocks

I have seen other related posts but could not find an answer to this particular case:/

This is a glibc bug (or long-standing glibc behavior, depending how you look at it):

It is difficult to fix in glibc because many applications assume that the line pointer does not have to be initialized when the length is zero, as in klutt 's original reply . If glibc started to free or otherwise use the line pointer in the zero length case, this would result in crashes.

Both getline and calloc allocates memory. If you want to use getline , don't preallocate. Just do this:

int main(void)
{   
    char *line = NULL;
    size_t size = 0;
    getline(&line, &size, stdin);
    free(line);
}

A hint to this is how you call getline . If you were sending line , the function would not be able to change what the pointer is pointing to. But now you are sending &line , which indicates that the function wants to reallocate the memory.

If you want to preallocate, use fgets instead of getline .

Also, main should not be a void function.

The size contained in size is the size of the current allocation pointed to by line . Thus the fix would be

#include <stdlib.h>
#include <stdio.h>
int main(void)
{   
    char *line = calloc(1024, 1);
    size_t size = 1024;
    getline(&line, &size, stdin);
    free(line);
}

and it is a-ok!

Alternatively you can do

char *line = NULL;
size_t size = 0;
getline(&line, &size, stdin);
free(line);

but it might do some extra reallocs for lines that are 1000 characters long.

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