29

我希望使用-fsanitize=memoryclang 中的标志来分析如下程序:

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

4

3 回答 3

18

当然,代码很好,但是许多类似的错误是由 clang 的内存清理工具的以下要求引起的:

MemorySanitizer(没有动态组件)要求检测整个程序代码,包括库(在某种程度上除了 libc/libm/libpthread)。

从这里

您正在使用 libstdc++ 的 cplusplus 运行时未经测试并导致错误。不幸的是,您将不得不按照该链接中描述的一些繁琐的过程来重建已检测的 libstdc++ 或切换到 libc++(更简单)

于 2013-12-26T11:33:37.343 回答
6

此时最简单的方法是使用 memorysanitizer 构建 libc++,然后将您的程序链接到它。

这就是我前段时间的做法,未能处理 libc++ 构建系统: https ://code.google.com/p/memory-sanitizer/source/browse/bootstrap/build_libcxx.sh

我听说 libc++ 方面有所改进,也许可以像往常一样构建它(使用 CC=/path/to/clang CFLAGS=-fsanitize=memory 之类的东西)。

于 2013-12-18T21:44:19.247 回答
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++ 运行时的检测构建。他们还建议您为此目的使用 LLVM libc++。请参阅Memory Sanitizer Libcxx HowToHow to unpoison a C++ std::string? 在 Memory Sanitizer 邮件列表中。

于 2016-02-27T15:14:43.803 回答