c++ - programas - Valgrind: memoria aún accesible con programa trivial usando<iostream>
ejercicios resueltos para dev-c++ pdf (3)
Considere el siguiente archivo de inclusión trivial:
#ifndef TRIVIAL_INCLUDE_FILE
#define TRIVIAL_INCLUDE_FILE
static int *x = new x (0);
#endif
Tome el siguiente programa trivial:
#include <iostream>
int main() {
return 0;
}
Si ejecuto esto usando valgrind, me dicen que hay
72,704 bytes in 1 blocks
que
still reachable
son
still reachable
.
Ha habido extensas discusiones sobre SO sobre si preocuparse o no por advertencias aún accesibles, no estoy preocupado por eso.
Solo me gustaría entender cómo la simple
inclusión de
un encabezado de biblioteca estándar podría causar una advertencia aún accesible, cuando ninguno de los objetos de esa biblioteca se asignaron en el programa en sí.
Aquí está la salida
valgrind
completa:
$ 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)
Y un volcado de objetos:
$ 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 <_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 $0x0
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 $0x1
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 $0x2
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 $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 <__libc_start_main@plt>
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 <_ZNSt8ios_base4InitC1Ev@plt>
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 <__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 $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
Para completar, estoy usando:
Ubuntu: 12.04
Valgrind: 3.10.1
3.7.0
g ++: 4.8.1
NB: Como nota al margen, esto no sucede cuando
<fstream>
otros encabezados como
<fstream>
o
<cmath>
.
Es culpa de Valgrind.
Primero,
-fsanitize=leak
no muestra nada.
En segundo lugar, Valgrind
states
que:
Antes que nada: relájate, probablemente no sea un error, sino una característica. Muchas implementaciones de las bibliotecas estándar de C ++ usan sus propios asignadores de agrupaciones de memoria. La memoria para un buen número de objetos destruidos no se libera de inmediato y se devuelve al sistema operativo, sino que se mantiene en los grupos para su posterior reutilización. El hecho de que las agrupaciones no se liberen al salir del programa hace que Valgrind informe que esta memoria aún es accesible. Sin embargo, el comportamiento de no liberar grupos en la salida podría llamarse un error de la biblioteca.
Usando GCC, puede forzar al STL a usar malloc y liberar memoria tan pronto como sea posible deshabilitando globalmente el almacenamiento en memoria caché. ¡Tener cuidado! Hacerlo probablemente ralentizará su programa, a veces drásticamente.
Con GCC 2.91, 2.95, 3.0 y 3.1, compile todas las fuentes utilizando el STL con -D__USE_MALLOC. ¡Tener cuidado! Esto se eliminó de GCC a partir de la versión 3.3.
Con GCC 3.2.2 y posterior, debe exportar la variable de entorno GLIBCPP_FORCE_NEW antes de ejecutar su programa.
Con GCC 3.4 y posterior, esa variable ha cambiado de nombre a GLIBCXX_FORCE_NEW.
[...]
Supongo que esos supuestos grupos de memoria se liberan
después de
la finalización del programa, en el llamado código de inicio que llama a
main
, entre otras configuraciones.
Las funciones internas definidas fuera del código del usuario deben tratarse como si no existieran, por eso Valgrind no puede (y no debería) ver más liberaciones.
Para gcc 6 y superior, llegó una corrección de error relacionada:
- Informe de error: "Advertencia sobre la memoria" aún accesible "cuando se usa libstdc ++ de gcc 5"
- Discusión sobre el rastreador de errores de Arch Linux
Con gcc 5, también puede obtener la misma advertencia sin incluir
iostream
.
Entonces, si ve una advertencia similar que se refiere a
dl-init.c
y está usando gcc 5, considere actualizar a una versión más nueva (gcc> = 6), o intente compilar con clang.