Valgrind: память по-прежнему доступна с тривиальной программой, используя <iostream>
Возьмите следующую тривиальную программу:
#include <iostream>
int main() {
return 0;
}
Если я запустил это с помощью valgrind, мне сказали, что есть 72,704 bytes in 1 blocks
, которые still reachable
. Там были подробно обсуждены вопросы о том, нужно ли беспокоиться о еще доступных предупреждениях - я не беспокоюсь об этом. Я просто хотел бы понять, как просто включение стандартного заголовка библиотеки может привести к еще доступному предупреждению, когда ни один из объектов из этой библиотеки не был выделен в самой программе.
Вот полный вывод 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)
И дамп объекта:
$ objdump -d ValgrindTest
ValgrindTest: file format elf64-x86-64
Disassembly of section .init:
0000000000400718 <_init>:
400718: 48 83 ec 08 sub $0x8,%rsp
40071c: e8 8b 00 00 00 callq 4007ac <call_gmon_start>
400721: 48 83 c4 08 add $0x8,%rsp
400725: c3 retq
Disassembly of section .plt:
0000000000400730 <[email protected]>:
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 <[email protected]>:
400740: ff 25 ba 08 20 00 jmpq *0x2008ba(%rip) # 601000 <_GLOBAL_OFFSET_TABLE_+0x18>
400746: 68 00 00 00 00 pushq $0x0
40074b: e9 e0 ff ff ff jmpq 400730 <_init+0x18>
0000000000400750 <[email protected]>:
400750: ff 25 b2 08 20 00 jmpq *0x2008b2(%rip) # 601008 <_GLOBAL_OFFSET_TABLE_+0x20>
400756: 68 01 00 00 00 pushq $0x1
40075b: e9 d0 ff ff ff jmpq 400730 <_init+0x18>
0000000000400760 <[email protected]>:
400760: ff 25 aa 08 20 00 jmpq *0x2008aa(%rip) # 601010 <_GLOBAL_OFFSET_TABLE_+0x28>
400766: 68 02 00 00 00 pushq $0x2
40076b: e9 c0 ff ff ff jmpq 400730 <_init+0x18>
0000000000400770 <[email protected]>:
400770: ff 25 a2 08 20 00 jmpq *0x2008a2(%rip) # 601018 <_GLOBAL_OFFSET_TABLE_+0x30>
400776: 68 03 00 00 00 pushq $0x3
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 $0xfffffffffffffff0,%rsp
40078d: 50 push %rax
40078e: 54 push %rsp
40078f: 49 c7 c0 80 09 40 00 mov $0x400980,%r8
400796: 48 c7 c1 f0 08 40 00 mov $0x4008f0,%rcx
40079d: 48 c7 c7 90 08 40 00 mov $0x400890,%rdi
4007a4: e8 a7 ff ff ff callq 400750 <[email protected]>
4007a9: f4 hlt
4007aa: 90 nop
4007ab: 90 nop
00000000004007ac <call_gmon_start>:
4007ac: 48 83 ec 08 sub $0x8,%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 $0x8,%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 $0x601037,%eax
4007d5: 55 push %rbp
4007d6: 48 2d 30 10 60 00 sub $0x601030,%rax
4007dc: 48 83 f8 0e cmp $0xe,%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 $0x0,%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 $0x601030,%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 $0x601030,%eax
400805: 55 push %rbp
400806: 48 2d 30 10 60 00 sub $0x601030,%rax
40080c: 48 c1 f8 03 sar $0x3,%rax
400810: 48 89 e5 mov %rsp,%rbp
400813: 48 89 c2 mov %rax,%rdx
400816: 48 c1 ea 3f shr $0x3f,%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 $0x0,%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 $0x601030,%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 $0x0,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 $0x1,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 $0x0,0x200580(%rip) # 600de8 <__JCR_END__>
400867: 00
400868: 74 1e je 400888 <frame_dummy+0x28>
40086a: b8 00 00 00 00 mov $0x0,%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 $0x600de8,%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 $0x0,%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 $0x10,%rsp
4008a3: 89 7d fc mov %edi,-0x4(%rbp)
4008a6: 89 75 f8 mov %esi,-0x8(%rbp)
4008a9: 83 7d fc 01 cmpl $0x1,-0x4(%rbp)
4008ad: 75 27 jne 4008d6 <_Z41__static_initialization_and_destruction_0ii+0x3b>
4008af: 81 7d f8 ff ff 00 00 cmpl $0xffff,-0x8(%rbp)
4008b6: 75 1e jne 4008d6 <_Z41__static_initialization_and_destruction_0ii+0x3b>
4008b8: bf 34 10 60 00 mov $0x601034,%edi
4008bd: e8 7e fe ff ff callq 400740 <[email protected]>
4008c2: ba 28 10 60 00 mov $0x601028,%edx
4008c7: be 34 10 60 00 mov $0x601034,%esi
4008cc: bf 70 07 40 00 mov $0x400770,%edi
4008d1: e8 8a fe ff ff callq 400760 <[email protected]>
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 $0xffff,%esi
4008e1: bf 01 00 00 00 mov $0x1,%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 $0x38,%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 $0x3,%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 $0x1,%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 $0x38,%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 $0x8,%rsp
400988: 48 83 c4 08 add $0x8,%rsp
40098c: c3 retq
Для полноты, я использую:
Ubuntu: 12.04
Valgrind: 3.10.1 3.7.0
g++: 4.8.1
NB: В качестве побочного примечания это не происходит, когда я включаю другие заголовки, такие как <fstream>
или <cmath>
.
Ответы
Ответ 1
Это ошибка Valgrind. Во-первых, -fsanitize=leak
ничего не показывает. Во-вторых, сам Valgrind утверждает, что:
Прежде всего: расслабься, наверное, это не ошибка, а особенность. Многие реализации стандартных библиотек С++ используют собственную память распределители пулов. Память для целого ряда разрушенных объектов не сразу освобождаются и возвращаются в ОС, но сохраняются в пул для последующего повторного использования. Тот факт, что пулы не освобождаются на выход программы заставляет Valgrind сообщать об этой памяти еще достижимы. Поведение не на свободные пулы на выходе можно было бы назвать ошибка библиотеки, хотя.
Используя GCC, вы можете заставить STL использовать malloc и освободить память как как можно скорее, глобально отключив кеширование памяти. Осторожно! дела так что, вероятно, замедлит вашу программу, иногда резко.
С GCC 2.91, 2.95, 3.0 и 3.1 скомпилируйте весь источник, используя STL с -D__USE_MALLOC. Осторожно! Это было удалено из GCC, начиная с версия 3.3.
С GCC 3.2.2 и более поздними версиями вы должны экспортировать переменную окружения GLIBCPP_FORCE_NEW перед запуском вашей программы.
С GCC 3.4 и более поздними версиями эта переменная изменила имя на GLIBCXX_FORCE_NEW.
[...]
Я предполагаю, что эти предполагаемые пулы памяти освобождаются после завершения программы, в так называемом стартовом коде, который вызывает main
, среди других параметров. Внутренние функции, определенные вне кода пользователя, должны обрабатываться так, как если бы они не существовали, поэтому Valgrind не может (и не должен) видеть дополнительные освобождения.
Ответ 2
Рассмотрим следующий тривиальный файл include:
#ifndef TRIVIAL_INCLUDE_FILE
#define TRIVIAL_INCLUDE_FILE
static int *x = new x (0);
#endif
Ответ 3
Для gcc 6 и выше появилось соответствующее исправление ошибки:
С gcc 5 вы также можете получить то же предупреждение, не включая iostream
.
Итак, если вы видите похожее предупреждение, относящееся к dl-init.c
и используете gcc 5, рассмотрите возможность обновления до более новой версии (gcc> = 6) или попробуйте скомпилировать с помощью clang.