Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
775 views
in Technique[技术] by (71.8m points)

c - Why doesn't valgrind spot the leak when program was compiled with gcc-5.2.0

Today I was coding something and after I was done, I made a check with valgrind and I got a surprise.

If I compile my program on my Ubuntu (15.04 64BIT) with gcc-4.9.2 with the following:

gcc -Wextra -Werror -Wstrict-prototypes -Wconversion --std=c11 -O2 -g program.c -o program

And then run valgrind:

valgrind --leak-check=full --track-origins=yes ./program

I get the following output:

==5325== Memcheck, a memory error detector
==5325== Copyright (C) 2002-2013, and GNU GPL'd, by Julian Seward et al.
==5325== Using Valgrind-3.10.1 and LibVEX; rerun with -h for copyright info
==5325== Command: ./program
==5325== 
Bye
==5325== 
==5325== HEAP SUMMARY:
==5325==     in use at exit: 33 bytes in 1 blocks
==5325==   total heap usage: 1 allocs, 0 frees, 33 bytes allocated
==5325== 
==5325== 33 bytes in 1 blocks are definitely lost in loss record 1 of 1
==5325==    at 0x4C2BBA0: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==5325==    by 0x4004BD: main (program.c:11)
==5325== 
==5325== LEAK SUMMARY:
==5325==    definitely lost: 33 bytes in 1 blocks
==5325==    indirectly lost: 0 bytes in 0 blocks
==5325==      possibly lost: 0 bytes in 0 blocks
==5325==    still reachable: 0 bytes in 0 blocks
==5325==         suppressed: 0 bytes in 0 blocks
==5325== 
==5325== For counts of detected and suppressed errors, rerun with: -v
==5325== ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 0 from 0)

As you can see the leak is spotted, but take a look of what happens if I compile with gcc-5.2.0 with the following:

./install/gcc-5.2.0/bin/gcc5.2 -Wextra -Werror -Wstrict-prototypes -Wconversion --std=c11 -O2 -g program.c -o program

And now valgrind says:

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

As you can see there is total heap usage: 0 allocs, 0 frees, 0 bytes allocated

The piece of code I tried was the following:

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

int main(void){
    int a = 0;
    size_t len1 = 0, len2 = 0;
    char *string1 = "Hello";
    char *string2;

    string2 = malloc(33);
    strcpy(string2, "Hello");

    len1 = strlen(string1);
    len2 = strlen(string2);

    if(len1 != len2){
        a = 5;
    }else{
        a=4;
    }

    while (a != -1){
        if(a == 2){
            break;
        }
        a--;
    }


    printf("Bye
");
    /*free(string2);*/
    return 0;
}

GCC-5.2.0 was installed using this method.

Now my question is: is it GCC or valgrind at fault? Why does this happen and how can I avoid it?

One last thing, if I change:

printf("Bye
");

to this:

printf("String2 = %s
",string2);

The leak is spotted:

==5443== Memcheck, a memory error detector
==5443== Copyright (C) 2002-2013, and GNU GPL'd, by Julian Seward et al.
==5443== Using Valgrind-3.10.1 and LibVEX; rerun with -h for copyright info
==5443== Command: ./program
==5443== 
String2 = Hello
==5443== 
==5443== HEAP SUMMARY:
==5443==     in use at exit: 33 bytes in 1 blocks
==5443==   total heap usage: 1 allocs, 0 frees, 33 bytes allocated
==5443== 
==5443== 33 bytes in 1 blocks are definitely lost in loss record 1 of 1
==5443==    at 0x4C2BBA0: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==5443==    by 0x40044D: main (program.c:11)
==5443== 
==5443== LEAK SUMMARY:
==5443==    definitely lost: 33 bytes in 1 blocks
==5443==    indirectly lost: 0 bytes in 0 blocks
==5443==      possibly lost: 0 bytes in 0 blocks
==5443==    still reachable: 0 bytes in 0 blocks
==5443==         suppressed: 0 bytes in 0 blocks
==5443== 
==5443== For counts of detected and suppressed errors, rerun with: -v
==5443== ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 0 from 0)

Which makes me ask myself why? Somehow printf() helps in this story.

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

Seems that GCC 5.2.0 is able to detect that string2 is a constant "Hello" through the strcpy. So it just optimizes out string2 without allocating new memory chunk in the HEAP. My guess would be that string.h has the implementation of strcpy and strlen in the header itself.

The best way to detect memory leaks is to compile without optimizations. Try recompiling it with -O0 instead of -O2. In this case the compiler will create the binary as close to your source code as possible.

With this:

printf("String2 = %s ",string2);

The leak is spotted:

Here it seems that the compiler detects dependency on string2 so it doesn't optimize it out. Probably because the implementation of printf is not available at the compilation time of your source or maybe because printf uses variadic variable. But it is just my guess...


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...