Подтвердить что ты не робот

Использование дезинфицирующего средства для памяти с помощью libstdС++

Я хочу использовать флаг -fsanitize=memory в clang для анализа следующей программы:

#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();
}

Насколько я знаю, эта программа верна, но когда я использую clang++ san.cpp -fsanitize=memory, она терпит неудачу (во время выполнения) с помощью:

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

Как я могу сделать это правильно?

Clang версия 3.5, stdlibС++ версия 6

4b9b3361

Ответ 1

Конечно, код хороший, но многие аналогичные ошибки вызывают следующее требование дезинфицирующего средства clang memory:

MemorySanitizer (без динамического компонента) требует, чтобы вся программа     код, включая библиотеки, (в частности, libc/libm/libpthread).

отсюда

Сценарий cplusplus, который вы используете libstdС++, unistrumented и вызывает ошибки. Вы, к сожалению, должны будете выполнить несколько неудобный процесс, как описано в этой ссылке, чтобы перестроить инструмент libstdС++ или перейти на libС++ (easy-ish)

Ответ 2

В этот раз проще всего построить libС++ с помощью memorysanitizer, а затем связать вашу программу с ней.

Вот как я это делал некоторое время назад, не справляясь с системой сборки libС++: https://code.google.com/p/memory-sanitizer/source/browse/bootstrap/build_libcxx.sh

Я слышал, что были улучшения на стороне libС++, возможно, было бы возможно построить его как обычно (с чем-то вроде CC =/path/to/clang CFLAGS = -fsanitize = memory).

Ответ 3

Как я могу сделать это правильно?

Вы также можете unpoison память, которая запускает обнаружение. Но неясно (для меня), какая переменная, основанная на показанной трассировке стека.

Здесь, как очистить память, но пример предназначен для памяти, используемой с FD_SET и FD_ZERO. Вам все равно нужно найти имя переменной, которая его вызывает (я не уверен, насколько хорошо указывается целостный адрес памяти).

#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)  

Вы можете получить дополнительную информацию о правонарушителях, запустив:

./myprog.exe 2>&1 | /usr/bin/asan_symbolize

Например, здесь программа, которую я пытаюсь проверить, имеет выход, похожий на ваш:

$ ./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)
    ...

Если вы хотите получить какое-то наказание, вы можете направить искаженное имя через 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&)

Наконец, по словам людей Msan, вам действительно нужна инструментальная сборка С++ Runtime. Они также рекомендуют использовать LLVM libc++ для этой цели. См. Memory Sanitizer Libcxx HowTo и Как отключить С++ std::string? в списке рассылки Sanitizer памяти.