为什么不当场Valgrind的泄漏方案是用gcc-5.2.0编译时 [英] Why doesn't valgrind spot the leak when program was compiled with gcc-5.2.0

查看:157
本文介绍了为什么不当场Valgrind的泄漏方案是用gcc-5.2.0编译时的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

今天,我被编码的东西,我做之后,我做了 的valgrind ,我得到了一个惊喜。

如果我编译我的程序在我的Ubuntu(15.04 64位)使用gcc-4.9.2与以下内容:

  GCC -Wextra -Werror -Wstrict的原型-Wconversion --std = C11 -O2 -g program.c -o程序

然后运行Valgrind的:

 的valgrind --leak检查=全--track-起源= YES ./program

我得到以下的输出:


  == == 5325 MEMCHECK,内存错误检测
== == 5325版权所有(C)2002至2013年,和GNU GPL的,Julian Seward写等。
== == 5325 Valgrind的使用-3.10.1和LibVEX;与-h版权信息重新运行
== == 5325命令:./program
== == 5325
再见
== == 5325
== == 5325 HEAP摘要:
== == 5325使用在出口处:在1块33个字节
== == 5325总堆的使用情况:1 allocs,0的FreeS,33字节分配
== == 5325
== == 5325在33块1个字节肯定失去了在负的战绩1 1
== == 5325在0x4C2BBA0:的malloc(以/usr/lib/valgrind/vg$p$pload_memcheck-amd64-linux.so)
== == 5325通过0x4004BD:主(program.c:11)
== == 5325
== == 5325泄漏摘要:
== == 5325肯定失去了33个字节的块1
== == 5325失去了间接:0字节0块
== == 5325可能丢失:0字节0块
== == 5325到达尚:0块0字节
== == 5325燮pressed:0字节0块
== == 5325
== == 5325对于检测燮pressed错误计数,重新运行:-v
== == 5325错误摘要:从1上下文1错误(SUP pressed:0 0)


正如你可以看到泄漏看准,但看看会发生什么,如果我编译GCC-5.2.0与以下内容:

  ./安装/ GCC-5.2.0 /斌/ gcc5.2 -Wextra -Werror -Wstrict的原型-Wconversion --std = C11 -O2 -g program.c  - O程序

和现在的valgrind说:


  == == 5344 MEMCHECK,内存错误检测
== == 5344版权所有(C)2002至2013年,和GNU GPL的,Julian Seward写等。
== == 5344 Valgrind的使用-3.10.1和LibVEX;与-h版权信息重新运行
== == 5344命令:./program
== == 5344
再见
== == 5344
== == 5344 HEAP摘要:
== == 5344使用在退出:0块0字节
== == 5344总堆的使用:0 allocs,0的FreeS,0字节分配
== == 5344
== == 5344的所有堆块被释放 - 无泄漏是可能的
== == 5344
== == 5344对于检测燮pressed错误计数,重新运行:-v
== == 5344错误摘要:从0 0上下文错误(SUP pressed:0 0)


正如你可以看到有总堆的使用:0 allocs,0的FreeS,0字节分配

我想这件作品code的是以下内容:

 #包括LT&;&stdio.h中GT;
#包括LT&;&stdlib.h中GT;
#包括LT&;&string.h中GT;诠释主要(无效){
    INT A = 0;
    为size_t LEN1 = 0,LEN2 = 0;
    字符*字符串1 =你好;
    字符*字符串2;    字符串2 =的malloc(33);
    的strcpy(字符串2,你好);    LEN1 = strlen的(字符串1);
    LEN2 = strlen的(字符串2);    如果(LEN1!= LEN2){
        1 = 5;
    }其他{
        一个= 4;
    }    而(A!= -1){
        如果(一个== 2){
            打破;
        }
        一个 - ;
    }
    的printf(再见\\ n);
    / *免费(字符串2); * /
    返回0;
}

GCC-5.2.0安装<一href=\"http://stackoverflow.com/questions/32771977/error-building-and-compiling-gcc-5-2-0-from-scratch-on-vortex86dx/32792077#32792077\">using这种方法。

现在我的问题是:这是GCC或Valgrind的过错?为什么会出现这种情况,我怎么能避免呢?

最后一件事,如果我改变:

 的printf(再见\\ n);

这样:

 的printf(字符串2 =%S \\ n,字符串2);

该泄漏的地点:


  == == 5443 MEMCHECK,内存错误检测
== == 5443版权所有(C)2002至2013年,和GNU GPL的,Julian Seward写等。
== == 5443 Valgrind的使用-3.10.1和LibVEX;与-h版权信息重新运行
== == 5443命令:./program
== == 5443
字符串2 =您好
== == 5443
== == 5443 HEAP摘要:
== == 5443使用在出口处:在1块33个字节
== == 5443总堆的使用情况:1 allocs,0的FreeS,33字节分配
== == 5443
== == 5443在33块1个字节肯定失去了在负的战绩1 1
== == 5443在0x4C2BBA0:的malloc(以/usr/lib/valgrind/vg$p$pload_memcheck-amd64-linux.so)
== == 5443通过0x40044D:主(program.c:11)
== == 5443
== == 5443泄漏摘要:
== == 5443肯定失去了33个字节的块1
== == 5443失去了间接:0字节0块
== == 5443可能丢失:0字节0块
== == 5443到达尚:0块0字节
== == 5443燮pressed:0字节0块
== == 5443
== == 5443对于检测燮pressed错误计数,重新运行:-v
== == 5443错误摘要:从1上下文1错误(SUP pressed:0 0)


这使我问自己,为什么?不知怎的,printf()的帮助,在这个故事。


解决方案

似乎GCC 5.2.0能够检测到字符串2 是一个常数你好通过的strcpy 。所以它只是优化了字符串2 而无需在堆中分配新的内存块。我的猜测是,文件string.h 的strcpy 的strlen 在头本身。

要检测内存泄漏的最好方法是不优化编译。试着用 -O0 重新编译它,而不是 -O2 。在这种情况下,编译器会创建二进制尽可能靠近源$ C ​​$ C越好。


  

这一点:


  
  

的printf(字符串2 =%S \\ n,字符串2);


  
  

该泄漏的地点:


这似乎编译器检测到字符串2 的依赖,因此它不会优化它。的大概是因为实施的printf 是不是可在您的源代码的编译时间或者也许是因为的printf 用途可变参数变量。但是,这只是我的猜测...

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\n");
    /*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\n");

to this:

printf("String2 = %s\n",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.

解决方案

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\n",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...

这篇关于为什么不当场Valgrind的泄漏方案是用gcc-5.2.0编译时的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆