C++ Valgrind:使用 <iostream> 的简单程序仍然可以访问内存

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/30376601/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-28 13:46:01  来源:igfitidea点击:

Valgrind: Memory still reachable with trivial program using <iostream>

c++valgrind

提问by sudo make install

Take the following trivial program:

采取以下琐碎的程序:

#include <iostream>
int main() {
  return 0;
}

If I run this using valgrind, I'm told that there are 72,704 bytes in 1 blocksthat are still reachable. There have been extensive discussions on SO about whether or not to worry about still reachable warnings--I'm not concerned about that. I'd just like to understand how simply includinga standard library header could cause a still reachable warning, when none of the objects from that library were allocated in the program itself.

如果我运行这个使用Valgrind的,我听说有72,704 bytes in 1 blocks那些still reachable。关于是否要担心仍然可以到达的警告,已经对 SO 进行了广泛的讨论——我并不担心。我只是想了解当程序本身中没有分配来自该库的任何对象时,仅包含标准库头文件如何导致仍然可到达的警告。

Here is the full valgrindoutput:

这是完整的valgrind输出:

$ valgrind --leak-check=full --track-origins=yes --show-reachable=yes ./ValgrindTest
==27671== Memcheck, a memory error detector
==27671== Copyright (C) 2002-2013, and GNU GPL'd, by Julian Seward et al.
==27671== Using Valgrind-3.10.1 and LibVEX; rerun with -h for copyright info
==27671== Command: ./ValgrindTest
==27671== 
==27671== 
==27671== HEAP SUMMARY:
==27671==     in use at exit: 72,704 bytes in 1 blocks
==27671==   total heap usage: 1 allocs, 0 frees, 72,704 bytes allocated
==27671== 
==27671== 72,704 bytes in 1 blocks are still reachable in loss record 1 of 1
==27671==    at 0x4C2AB9D: malloc (vg_replace_malloc.c:296)
==27671==    by 0x4EC060F: ??? (in /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.21)
==27671==    by 0x400F305: call_init.part.0 (dl-init.c:85)
==27671==    by 0x400F3DE: call_init (dl-init.c:52)
==27671==    by 0x400F3DE: _dl_init (dl-init.c:134)
==27671==    by 0x40016E9: ??? (in /lib/x86_64-linux-gnu/ld-2.15.so)
==27671== 
==27671== LEAK SUMMARY:
==27671==    definitely lost: 0 bytes in 0 blocks
==27671==    indirectly lost: 0 bytes in 0 blocks
==27671==      possibly lost: 0 bytes in 0 blocks
==27671==    still reachable: 72,704 bytes in 1 blocks
==27671==         suppressed: 0 bytes in 0 blocks
==27671== 
==27671== For counts of detected and suppressed errors, rerun with: -v
==27671== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)

And an object dump:

和一个对象转储:

$ objdump -d ValgrindTest 

ValgrindTest:     file format elf64-x86-64


Disassembly of section .init:

0000000000400718 <_init>:
  400718:   48 83 ec 08             sub    
#ifndef TRIVIAL_INCLUDE_FILE
#define TRIVIAL_INCLUDE_FILE
static int *x = new x (0);
#endif
x8,%rsp 40071c: e8 8b 00 00 00 callq 4007ac <call_gmon_start> 400721: 48 83 c4 08 add ##代码##x8,%rsp 400725: c3 retq Disassembly of section .plt: 0000000000400730 <_ZNSt8ios_base4InitC1Ev@plt-0x10>: 400730: ff 35 ba 08 20 00 pushq 0x2008ba(%rip) # 600ff0 <_GLOBAL_OFFSET_TABLE_+0x8> 400736: ff 25 bc 08 20 00 jmpq *0x2008bc(%rip) # 600ff8 <_GLOBAL_OFFSET_TABLE_+0x10> 40073c: 0f 1f 40 00 nopl 0x0(%rax) 0000000000400740 <_ZNSt8ios_base4InitC1Ev@plt>: 400740: ff 25 ba 08 20 00 jmpq *0x2008ba(%rip) # 601000 <_GLOBAL_OFFSET_TABLE_+0x18> 400746: 68 00 00 00 00 pushq ##代码##x0 40074b: e9 e0 ff ff ff jmpq 400730 <_init+0x18> 0000000000400750 <__libc_start_main@plt>: 400750: ff 25 b2 08 20 00 jmpq *0x2008b2(%rip) # 601008 <_GLOBAL_OFFSET_TABLE_+0x20> 400756: 68 01 00 00 00 pushq ##代码##x1 40075b: e9 d0 ff ff ff jmpq 400730 <_init+0x18> 0000000000400760 <__cxa_atexit@plt>: 400760: ff 25 aa 08 20 00 jmpq *0x2008aa(%rip) # 601010 <_GLOBAL_OFFSET_TABLE_+0x28> 400766: 68 02 00 00 00 pushq ##代码##x2 40076b: e9 c0 ff ff ff jmpq 400730 <_init+0x18> 0000000000400770 <_ZNSt8ios_base4InitD1Ev@plt>: 400770: ff 25 a2 08 20 00 jmpq *0x2008a2(%rip) # 601018 <_GLOBAL_OFFSET_TABLE_+0x30> 400776: 68 03 00 00 00 pushq ##代码##x3 40077b: e9 b0 ff ff ff jmpq 400730 <_init+0x18> Disassembly of section .text: 0000000000400780 <_start>: 400780: 31 ed xor %ebp,%ebp 400782: 49 89 d1 mov %rdx,%r9 400785: 5e pop %rsi 400786: 48 89 e2 mov %rsp,%rdx 400789: 48 83 e4 f0 and ##代码##xfffffffffffffff0,%rsp 40078d: 50 push %rax 40078e: 54 push %rsp 40078f: 49 c7 c0 80 09 40 00 mov ##代码##x400980,%r8 400796: 48 c7 c1 f0 08 40 00 mov ##代码##x4008f0,%rcx 40079d: 48 c7 c7 90 08 40 00 mov ##代码##x400890,%rdi 4007a4: e8 a7 ff ff ff callq 400750 <__libc_start_main@plt> 4007a9: f4 hlt 4007aa: 90 nop 4007ab: 90 nop 00000000004007ac <call_gmon_start>: 4007ac: 48 83 ec 08 sub ##代码##x8,%rsp 4007b0: 48 8b 05 29 08 20 00 mov 0x200829(%rip),%rax # 600fe0 <_DYNAMIC+0x1f0> 4007b7: 48 85 c0 test %rax,%rax 4007ba: 74 02 je 4007be <call_gmon_start+0x12> 4007bc: ff d0 callq *%rax 4007be: 48 83 c4 08 add ##代码##x8,%rsp 4007c2: c3 retq 4007c3: 90 nop 4007c4: 90 nop 4007c5: 90 nop 4007c6: 90 nop 4007c7: 90 nop 4007c8: 90 nop 4007c9: 90 nop 4007ca: 90 nop 4007cb: 90 nop 4007cc: 90 nop 4007cd: 90 nop 4007ce: 90 nop 4007cf: 90 nop 00000000004007d0 <deregister_tm_clones>: 4007d0: b8 37 10 60 00 mov ##代码##x601037,%eax 4007d5: 55 push %rbp 4007d6: 48 2d 30 10 60 00 sub ##代码##x601030,%rax 4007dc: 48 83 f8 0e cmp ##代码##xe,%rax 4007e0: 48 89 e5 mov %rsp,%rbp 4007e3: 77 02 ja 4007e7 <deregister_tm_clones+0x17> 4007e5: 5d pop %rbp 4007e6: c3 retq 4007e7: b8 00 00 00 00 mov ##代码##x0,%eax 4007ec: 48 85 c0 test %rax,%rax 4007ef: 74 f4 je 4007e5 <deregister_tm_clones+0x15> 4007f1: 5d pop %rbp 4007f2: bf 30 10 60 00 mov ##代码##x601030,%edi 4007f7: ff e0 jmpq *%rax 4007f9: 0f 1f 80 00 00 00 00 nopl 0x0(%rax) 0000000000400800 <register_tm_clones>: 400800: b8 30 10 60 00 mov ##代码##x601030,%eax 400805: 55 push %rbp 400806: 48 2d 30 10 60 00 sub ##代码##x601030,%rax 40080c: 48 c1 f8 03 sar ##代码##x3,%rax 400810: 48 89 e5 mov %rsp,%rbp 400813: 48 89 c2 mov %rax,%rdx 400816: 48 c1 ea 3f shr ##代码##x3f,%rdx 40081a: 48 01 d0 add %rdx,%rax 40081d: 48 d1 f8 sar %rax 400820: 75 02 jne 400824 <register_tm_clones+0x24> 400822: 5d pop %rbp 400823: c3 retq 400824: ba 00 00 00 00 mov ##代码##x0,%edx 400829: 48 85 d2 test %rdx,%rdx 40082c: 74 f4 je 400822 <register_tm_clones+0x22> 40082e: 5d pop %rbp 40082f: 48 89 c6 mov %rax,%rsi 400832: bf 30 10 60 00 mov ##代码##x601030,%edi 400837: ff e2 jmpq *%rdx 400839: 0f 1f 80 00 00 00 00 nopl 0x0(%rax) 0000000000400840 <__do_global_dtors_aux>: 400840: 80 3d e9 07 20 00 00 cmpb ##代码##x0,0x2007e9(%rip) # 601030 <__bss_start> 400847: 75 11 jne 40085a <__do_global_dtors_aux+0x1a> 400849: 55 push %rbp 40084a: 48 89 e5 mov %rsp,%rbp 40084d: e8 7e ff ff ff callq 4007d0 <deregister_tm_clones> 400852: 5d pop %rbp 400853: c6 05 d6 07 20 00 01 movb ##代码##x1,0x2007d6(%rip) # 601030 <__bss_start> 40085a: f3 c3 repz retq 40085c: 0f 1f 40 00 nopl 0x0(%rax) 0000000000400860 <frame_dummy>: 400860: 48 83 3d 80 05 20 00 cmpq ##代码##x0,0x200580(%rip) # 600de8 <__JCR_END__> 400867: 00 400868: 74 1e je 400888 <frame_dummy+0x28> 40086a: b8 00 00 00 00 mov ##代码##x0,%eax 40086f: 48 85 c0 test %rax,%rax 400872: 74 14 je 400888 <frame_dummy+0x28> 400874: 55 push %rbp 400875: bf e8 0d 60 00 mov ##代码##x600de8,%edi 40087a: 48 89 e5 mov %rsp,%rbp 40087d: ff d0 callq *%rax 40087f: 5d pop %rbp 400880: e9 7b ff ff ff jmpq 400800 <register_tm_clones> 400885: 0f 1f 00 nopl (%rax) 400888: e9 73 ff ff ff jmpq 400800 <register_tm_clones> 40088d: 90 nop 40088e: 90 nop 40088f: 90 nop 0000000000400890 <main>: 400890: 55 push %rbp 400891: 48 89 e5 mov %rsp,%rbp 400894: b8 00 00 00 00 mov ##代码##x0,%eax 400899: 5d pop %rbp 40089a: c3 retq 000000000040089b <_Z41__static_initialization_and_destruction_0ii>: 40089b: 55 push %rbp 40089c: 48 89 e5 mov %rsp,%rbp 40089f: 48 83 ec 10 sub ##代码##x10,%rsp 4008a3: 89 7d fc mov %edi,-0x4(%rbp) 4008a6: 89 75 f8 mov %esi,-0x8(%rbp) 4008a9: 83 7d fc 01 cmpl ##代码##x1,-0x4(%rbp) 4008ad: 75 27 jne 4008d6 <_Z41__static_initialization_and_destruction_0ii+0x3b> 4008af: 81 7d f8 ff ff 00 00 cmpl ##代码##xffff,-0x8(%rbp) 4008b6: 75 1e jne 4008d6 <_Z41__static_initialization_and_destruction_0ii+0x3b> 4008b8: bf 34 10 60 00 mov ##代码##x601034,%edi 4008bd: e8 7e fe ff ff callq 400740 <_ZNSt8ios_base4InitC1Ev@plt> 4008c2: ba 28 10 60 00 mov ##代码##x601028,%edx 4008c7: be 34 10 60 00 mov ##代码##x601034,%esi 4008cc: bf 70 07 40 00 mov ##代码##x400770,%edi 4008d1: e8 8a fe ff ff callq 400760 <__cxa_atexit@plt> 4008d6: c9 leaveq 4008d7: c3 retq 00000000004008d8 <_GLOBAL__sub_I_main>: 4008d8: 55 push %rbp 4008d9: 48 89 e5 mov %rsp,%rbp 4008dc: be ff ff 00 00 mov ##代码##xffff,%esi 4008e1: bf 01 00 00 00 mov ##代码##x1,%edi 4008e6: e8 b0 ff ff ff callq 40089b <_Z41__static_initialization_and_destruction_0ii> 4008eb: 5d pop %rbp 4008ec: c3 retq 4008ed: 90 nop 4008ee: 90 nop 4008ef: 90 nop 00000000004008f0 <__libc_csu_init>: 4008f0: 48 89 6c 24 d8 mov %rbp,-0x28(%rsp) 4008f5: 4c 89 64 24 e0 mov %r12,-0x20(%rsp) 4008fa: 48 8d 2d df 04 20 00 lea 0x2004df(%rip),%rbp # 600de0 <__init_array_end> 400901: 4c 8d 25 c8 04 20 00 lea 0x2004c8(%rip),%r12 # 600dd0 <__frame_dummy_init_array_entry> 400908: 4c 89 6c 24 e8 mov %r13,-0x18(%rsp) 40090d: 4c 89 74 24 f0 mov %r14,-0x10(%rsp) 400912: 4c 89 7c 24 f8 mov %r15,-0x8(%rsp) 400917: 48 89 5c 24 d0 mov %rbx,-0x30(%rsp) 40091c: 48 83 ec 38 sub ##代码##x38,%rsp 400920: 4c 29 e5 sub %r12,%rbp 400923: 41 89 fd mov %edi,%r13d 400926: 49 89 f6 mov %rsi,%r14 400929: 48 c1 fd 03 sar ##代码##x3,%rbp 40092d: 49 89 d7 mov %rdx,%r15 400930: e8 e3 fd ff ff callq 400718 <_init> 400935: 48 85 ed test %rbp,%rbp 400938: 74 1c je 400956 <__libc_csu_init+0x66> 40093a: 31 db xor %ebx,%ebx 40093c: 0f 1f 40 00 nopl 0x0(%rax) 400940: 4c 89 fa mov %r15,%rdx 400943: 4c 89 f6 mov %r14,%rsi 400946: 44 89 ef mov %r13d,%edi 400949: 41 ff 14 dc callq *(%r12,%rbx,8) 40094d: 48 83 c3 01 add ##代码##x1,%rbx 400951: 48 39 eb cmp %rbp,%rbx 400954: 75 ea jne 400940 <__libc_csu_init+0x50> 400956: 48 8b 5c 24 08 mov 0x8(%rsp),%rbx 40095b: 48 8b 6c 24 10 mov 0x10(%rsp),%rbp 400960: 4c 8b 64 24 18 mov 0x18(%rsp),%r12 400965: 4c 8b 6c 24 20 mov 0x20(%rsp),%r13 40096a: 4c 8b 74 24 28 mov 0x28(%rsp),%r14 40096f: 4c 8b 7c 24 30 mov 0x30(%rsp),%r15 400974: 48 83 c4 38 add ##代码##x38,%rsp 400978: c3 retq 400979: 0f 1f 80 00 00 00 00 nopl 0x0(%rax) 0000000000400980 <__libc_csu_fini>: 400980: f3 c3 repz retq 400982: 90 nop 400983: 90 nop Disassembly of section .fini: 0000000000400984 <_fini>: 400984: 48 83 ec 08 sub ##代码##x8,%rsp 400988: 48 83 c4 08 add ##代码##x8,%rsp 40098c: c3 retq

For completeness, I'm using:
Ubuntu: 12.04
Valgrind: 3.10.1 3.7.0
g++: 4.8.1

为了完整
起见,我使用:Ubuntu:12.04
Valgrind:3.10.1 3.7.0
g++:4.8.1

NB: As a side note, this does not happen when I include other headers such as <fstream>or <cmath>.

注意:作为旁注,当我包含其他标题时不会发生这种情况,例如<fstream><cmath>

采纳答案by edmz

It's Valgrind's fault. First, -fsanitize=leakdoes not show anything. Second, Valgrind itself statesthat:

这是瓦尔格林德的错。首先,-fsanitize=leak不显示任何东西。其次,Valgrind 本身指出

First of all: relax, it's probably not a bug, but a feature. Many implementations of the C++ standard libraries use their own memory pool allocators. Memory for quite a number of destructed objects is not immediately freed and given back to the OS, but kept in the pool(s) for later re-use. The fact that the pools are not freed at the exit of the program cause Valgrind to report this memory as still reachable. The behaviour not to free pools at the exit could be called a bug of the library though.

Using GCC, you can force the STL to use malloc and to free memory as soon as possible by globally disabling memory caching. Beware! Doing so will probably slow down your program, sometimes drastically.

With GCC 2.91, 2.95, 3.0 and 3.1, compile all source using the STL with -D__USE_MALLOC. Beware! This was removed from GCC starting with version 3.3.

With GCC 3.2.2 and later, you should export the environment variable GLIBCPP_FORCE_NEW before running your program.

With GCC 3.4 and later, that variable has changed name to GLIBCXX_FORCE_NEW.

[...]

首先:放松,这可能不是一个错误,而是一个功能。C++ 标准库的许多实现使用它们自己的内存池分配器。相当多的被破坏对象的内存不会立即释放并返回给操作系统,而是保留在池中供以后重用。在程序退出时池未释放的事实导致 Valgrind 报告此内存仍可访问。不过,在出口处不释放池的行为可能被称为库的错误。

使用 GCC,您可以强制 STL 使用 malloc 并通过全局禁用内存缓存来尽快释放内存。谨防!这样做可能会减慢你的程序,有时会显着减慢。

对于 GCC 2.91、2.95、3.0 和 3.1,使用带有 -D__USE_MALLOC 的 STL 编译所有源代码。谨防!从 3.3 版开始,这已从 GCC 中删除。

对于 GCC 3.2.2 及更高版本,您应该在运行程序之前导出环境变量 GLIBCPP_FORCE_NEW。

在 GCC 3.4 及更高版本中,该变量已更改名称为 GLIBCXX_FORCE_NEW。

[...]

I guess those alleged memory pools are freed afterprogram's termination, in the so-called start-up code that calls main, among the other settings. Internal functions defined outside user's code should be treated as if they didn't exist, that's why Valgrind can't (and shouldn't) see further frees.

我猜那些所谓的内存池程序终止后被释放,在所谓的启动代码中调用main,以及其他设置。在用户代码之外定义的内部函数应该被视为它们不存在,这就是为什么 Valgrind 不能(也不应该)看到更多的释放。

回答by David Schwartz

Consider the following trivial include file:

考虑以下简单的包含文件:

##代码##

回答by Philipp Cla?en

For gcc 6 and higher, a related bug fix arrived:

对于 gcc 6 及更高版本,一个相关的错误修复到达:

With gcc 5, you can also get the same warning without including iostream.

使用 gcc 5,您也可以在不包含iostream.

So, if you see a similar warning referring to dl-init.cand you are using gcc 5, consider upgrading to a newer version (gcc >=6), or try to compile with clang.

因此,如果您看到类似的警告,dl-init.c并且您正在使用 gcc 5,请考虑升级到更新的版本 (gcc >=6),或尝试使用 clang 进行编译。