我希望在clang中使用-fsanitize=memory
标志来分析如下的程序:
#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,stdlibc ++版本6
答案 0 :(得分:16)
代码很好,当然但是许多类似的错误是由clang的内存消毒工具的以下要求引起的:
MemorySanitizer(没有动态组件)需要整个程序 代码包括库,(在某种程度上除了libc / libm / libpthread),已经过检测。
您使用libstdc ++的cplusplus运行时是未经检测的并导致错误。遗憾的是,您必须遵循该链接中描述的有点繁琐的过程来重建已检测的libstdc ++或切换到libc ++(更简单的方法)
答案 1 :(得分:5)
目前最简单的方法是使用memorysanitizer构建libc ++,然后将程序链接到它。
这是我前一段时间做的,未能处理libc ++构建系统: https://code.google.com/p/memory-sanitizer/source/browse/bootstrap/build_libcxx.sh
我听说libc ++方面有所改进,也许可以照常构建它(比如CC = / path / to / clang CFLAGS = -fsanitize = memory)。
答案 2 :(得分:2)
如何正常运作?
您还可以 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人员说,你真的需要一个C ++ Runtime的检测版本。他们还建议您使用LLVM的 libc++
。请参阅Memory Sanitizer邮件列表中的Memory Sanitizer Libcxx HowTo和How to unpoison a C++ std::string?。