为什么用gcc-5.2.0编译程序时valgrind没有发现泄漏 [英] Why doesn't valgrind spot the leak when program was compiled with gcc-5.2.0

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

问题描述

今天我正在编写一些代码,完成后,我使用 valgrind 进行了检查 我得到了一个惊喜.

如果我在我的 Ubuntu (15.04 64BIT) 上用 gcc-4.9.2 编译我的程序,如下:

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

然后运行valgrind:

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

我得到以下输出:

<块引用>

==5325== Memcheck,一个内存错误检测器==5325== 版权所有 (C) 2002-2013 和 GNU GPL,由 Julian Seward 等人所有.==5325== 使用 Valgrind-3.10.1 和 LibVEX;使用 -h 重新运行以获取版权信息==5325== 命令:./program==5325==再见==5325====5325== 堆摘要:==5325== 退出时使用:1 个块中的 33 个字节==5325== 总堆使用量:1 次分配,0 次释放,已分配 33 个字节==5325====5325== 1 个块中的 33 个字节在丢失记录 1 of 1 中肯定丢失==5325== 在 0x4C2BBA0:malloc(在/usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so 中)==5325== 由 0x4004BD: main (program.c:11)==5325====5325== 泄漏摘要:==5325== 肯定丢失了:1 个块中的 33 个字节==5325== 间接丢失:0 个块中的 0 个字节==5325== 可能丢失:0 个块中的 0 个字节==5325== 仍然可达:0 个块中的 0 个字节==5325== 抑制:0 个块中的 0 个字节==5325====5325== 对于检测到和抑制的错误的计数,重新运行: -v==5325== 错误摘要:来自 1 个上下文的 1 个错误(被抑制:来自 0 的 0)

如您所见,泄漏已被发现,但看看我使用 gcc-5.2.0 编译时会发生什么:

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

现在 valgrind 说:

<块引用>

==5344== Memcheck,一个内存错误检测器==5344== 版权所有 (C) 2002-2013 和 GNU GPL,由 Julian Seward 等人所有.==5344== 使用 Valgrind-3.10.1 和 LibVEX;使用 -h 重新运行以获取版权信息==5344== 命令:./program==5344==再见==5344====5344== 堆摘要:==5344== 退出时正在使用:0 个块中的 0 个字节==5344== 总堆使用量:0 分配,0 释放,0 字节分配==5344====5344== 所有堆块都被释放——不可能有泄漏==5344====5344== 对于检测到和抑制的错误的计数,重新运行: -v==5344== 错误摘要:0 个上下文中的 0 个错误(被抑制:0 个中的 0 个错误)

如您所见,总的堆使用量:0 分配,0 释放,0 字节分配

我尝试的代码如下:

#include#include#includeint main(void){int a = 0;size_t len1 = 0, len2 = 0;char *string1 = "你好";字符 *string2;string2 = malloc(33);strcpy(string2, "你好");len1 = strlen(string1);len2 = strlen(string2);如果(len1 != len2){一 = 5;}别的{a=4;}而 (a != -1){如果(a == 2){休息;}一个 - ;}printf("再见
");/*自由(字符串2);*/返回0;}

已安装 GCC-5.2.0 使用这种方法.

现在我的问题是:是 GCC 还是 valgrind 有问题?为什么会发生这种情况,我该如何避免?

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

printf("再见
");

为此:

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

发现泄漏:

<块引用>

==5443== Memcheck,一个内存错误检测器==5443== 版权所有 (C) 2002-2013 和 GNU GPL,由 Julian Seward 等人所有.==5443== 使用 Valgrind-3.10.1 和 LibVEX;使用 -h 重新运行以获取版权信息==5443== 命令:./program==5443==String2 = 你好==5443====5443== 堆摘要:==5443== 在退出时使用:1 个块中的 33 个字节==5443== 总堆使用量:1 次分配,0 次释放,已分配 33 个字节==5443====5443== 1 个块中的 33 个字节在丢失记录 1 of 1 中肯定丢失==5443== 在 0x4C2BBA0:malloc(在/usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so 中)==5443== 由 0x40044D: main (program.c:11)==5443====5443== 泄漏摘要:==5443== 肯定丢失了:1 个块中的 33 个字节==5443== 间接丢失:0 个块中的 0 个字节==5443== 可能丢失:0 个块中的 0 个字节==5443== 仍然可达:0 个块中的 0 个字节==5443== 被抑制:0 个块中的 0 个字节==5443====5443== 对于检测到和抑制的错误的计数,重新运行: -v==5443== 错误摘要:1 个上下文中的 1 个错误(被抑制:0 中的 0)

这让我问自己为什么?不知何故 printf() 在这个故事中有所帮助.

解决方案

似乎 GCC 5.2.0 能够检测到 string2 是一个常量 "Hello" 通过strcpy.所以它只是优化了 string2 而不在 HEAP 中分配新的内存块.我的猜测是 string.h 在标头本身中具有 strcpystrlen 的实现.

检测内存泄漏的最佳方法是在没有优化的情况下进行编译.尝试使用 -O0 而不是 -O2 重新编译它.在这种情况下,编译器将创建尽可能接近源代码的二进制文件.

<块引用>

有了这个:

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

发现泄漏:

这里似乎编译器检测到对 string2 的依赖,所以它没有优化它.可能是因为 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
");
    /*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.

解决方案

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

这篇关于为什么用gcc-5.2.0编译程序时valgrind没有发现泄漏的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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