Usar el desinfectante de memoria con libstdc++
clang++ msan (3)
Deseo utilizar el -fsanitize=memory
en clang para analizar un programa como el siguiente:
#include <string>
#include <iostream>
#include <fstream>
using namespace std;
void writeToFile(){
ofstream o;
o.open("dum");
o<<"test"<<endl; //The error is here.
//It does not matter if the file is opened this way,
//or with o("dum");
o.close();
}
int main(){
writeToFile();
}
Por lo que sé, este programa es correcto, pero cuando uso clang++ san.cpp -fsanitize=memory
, falla (en tiempo de ejecución) con:
UMR in __interceptor_write at offset 0 inside [0x64800000e000, +5)
==9685== WARNING: MemorySanitizer: use-of-uninitialized-value
#0 0x7f48d0899ae5 (/usr/lib/x86_64-linux-gnu/libstdc++.so.6+0x7bae5)
#1 0x7f48d08d1787 (/usr/lib/x86_64-linux-gnu/libstdc++.so.6+0xb3787)
#2 0x7f48d08d21e2 (/usr/lib/x86_64-linux-gnu/libstdc++.so.6+0xb41e2)
#3 0x7f48d08cfd1e (/usr/lib/x86_64-linux-gnu/libstdc++.so.6+0xb1d1e)
#4 0x7f48d08b1f2d (/usr/lib/x86_64-linux-gnu/libstdc++.so.6+0x93f2d)
#5 0x7f48d16d60f5 in writeToFile() /home/daniel/programming/test/santest.cpp:10
#6 0x7f48d16d61f4 in main /home/daniel/programming/test/santest.cpp:15
#7 0x7f48d0261de4 (/lib/x86_64-linux-gnu/libc.so.6+0x21de4)
#8 0x7f48d16d5e42 in _start (/home/daniel/programming/test/a.out+0x61e42)
SUMMARY: MemorySanitizer: use-of-uninitialized-value ??:0 ??
¿Cómo puedo hacer que esto funcione correctamente?
Clang versión 3.5, stdlibc ++ versión 6
La manera más fácil en este momento es construir libc ++ con memorysanitizer, luego vincular su programa con este.
Así es como lo hice hace un tiempo, al no poder manejar el sistema de compilación libc ++: https://code.google.com/p/memory-sanitizer/source/browse/bootstrap/build_libcxx.sh
Escuché que ha habido mejoras en el lado de libc ++, tal vez sería posible construirlo como de costumbre (con algo como CC = / ruta / a / clang CFLAGS = -fsanitize = memoria).
El código está bien, por supuesto, pero muchos errores similares son causados por el siguiente requisito de la herramienta de desinfección de memoria de clang:
MemorySanitizer (sin un componente dinámico) requiere que esté instrumentado todo el código del programa, incluidas las bibliotecas, (excepto libc / libm / libpthread, en cierta medida).
El tiempo de ejecución de cplusplus que está utilizando libstdc ++ no está instrumentalizado y causa errores. Desgraciadamente, tendrá que seguir un proceso algo complicado como se describe en ese enlace para reconstruir un libstdc ++ instrumentado o cambiar a libc ++ (más fácil-ish)
¿Cómo puedo hacer que esto funcione correctamente?
También puede unpoison
la memoria que está desencadenando el hallazgo. Pero no está claro (para mí) qué variable se basa en el seguimiento de la pila que se muestra.
Aquí se explica cómo deshacer la memoria, pero el ejemplo es para la memoria utilizada con FD_SET
y FD_ZERO
. Todavía necesitará encontrar el nombre de la variable que lo está causando (no estoy seguro de cuán bien funciona la especificación de una dirección de memoria integral).
#include <sanitizer/msan_interface.h>
...
__msan_unpoison(&readfds, sizeof(readfds));
__msan_unpoison(&writefds, sizeof(writefds));
UMR in __interceptor_write at offset 0 inside [0x64800000e000, +5)
==9685== WARNING: MemorySanitizer: use-of-uninitialized-value
#0 0x7f48d0899ae5 (/usr/lib/x86_64-linux-gnu/libstdc++.so.6+0x7bae5)
#1 0x7f48d08d1787 (/usr/lib/x86_64-linux-gnu/libstdc++.so.6+0xb3787)
#2 0x7f48d08d21e2 (/usr/lib/x86_64-linux-gnu/libstdc++.so.6+0xb41e2)
#3 0x7f48d08cfd1e (/usr/lib/x86_64-linux-gnu/libstdc++.so.6+0xb1d1e)
#4 0x7f48d08b1f2d (/usr/lib/x86_64-linux-gnu/libstdc++.so.6+0x93f2d)
#5 0x7f48d16d60f5 in writeToFile() /home/daniel/programming/test/santest.cpp:10
#6 0x7f48d16d61f4 in main /home/daniel/programming/test/santest.cpp:15
#7 0x7f48d0261de4 (/lib/x86_64-linux-gnu/libc.so.6+0x21de4)
#8 0x7f48d16d5e42 in _start (/home/daniel/programming/test/a.out+0x61e42)
Puede obtener más información sobre los delincuentes ejecutando:
./myprog.exe 2>&1 | /usr/bin/asan_symbolize
Por ejemplo, he aquí un programa que intento probar que tiene un resultado similar al tuyo:
$ ./cryptest.exe v 2>&1 | /usr/bin/asan_symbolize
==26988== WARNING: MemorySanitizer: use-of-uninitialized-value
#0 0x7f51903b2ca8 in _ZNSt8_Rb_treeISsSt4pairIKSsPvESt10_Select1stIS3_ESt4lessISsESaIS3_EE14_M_lower_boundEPSt13_Rb_tree_nodeIS3_ESC_RS1_ /usr/bin/../lib/gcc/x86_64-linux-gnu/4.9/../../../../include/c++/4.9/bits/stl_tree.h:1260 (discriminator 1)
...
Si está buscando un castigo, puede canalizar el nombre destrozado a través de c++filt
y obtener un nombre no c++filt
:
$ echo " _ZNSt8_Rb_treeISsSt4pairIKSsPvESt10_Select1stIS3_ESt4lessISsESaIS3_EE14_M_lower_boundEPSt13_Rb_tree_nodeIS3_ESC_RS1_" | c++filt
std::_Rb_tree<std::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::pair<std::basic_string<char, std::char_traits<char>, std::allocator<char> > const, void*>, std::_Select1st<std::pair<std::basic_string<char, std::char_traits<char>, std::allocator<char> > const, void*> >, std::less<std::basic_string<char, std::char_traits<char>, std::allocator<char> > >, std::allocator<std::pair<std::basic_string<char, std::char_traits<char>, std::allocator<char> > const, void*> > >::_M_lower_bound(std::_Rb_tree_node<std::pair<std::basic_string<char, std::char_traits<char>, std::allocator<char> > const, void*> >*, std::_Rb_tree_node<std::pair<std::basic_string<char, std::char_traits<char>, std::allocator<char> > const, void*> >*, std::basic_string<char, std::char_traits<char>, std::allocator<char> > const&)
Finalmente, según la gente de Msan, realmente necesitas una compilación instrumentada del C ++ Runtime. También recomiendan usar el libc++
LLVM para este propósito. Consulte Memory Sanitizer Libcxx HowTo y cómo desvelar C ++ std :: string? en la lista de correo de Memory Sanitizer.