clang 内存消毒剂报告使用非处方化值
clang++ memory sanitizer reports use-of-uninitialized-value
此代码是从Inclublos github页面中获取的。我对其进行了一些修改,以便它在没有其他标头文件的情况下进行编译。includeos的 find
函数有点冗长,所以我想简化它。但是经过修改后,代码的行为与我预期的不同。
这是一个简短的解释。此代码用于解析HTTP标头。标题字段是名称值对。它表示为vector<pair<string, string>>
。find
功能用于在标题中查找字段名称的位置,并且has_field
用于检查标题中是否存在特定的字段名称。
在main
功能中,将四个元素附加到字段上。six
不应在字段中找到。但has_field
返回True。
我尝试使用gdb
跟踪错误。但是我在产出的海洋中迷路了。我确实找到了一个有趣的消息。
std :: __ unitialized_copy&lt; :: __ __ uninit_copy&lt; __ gnu_cxx :: __ normal_ertorator&std :: pair&lt :: pair&lt; std :: __ __ __ cxx11 :: basic_string&car car char,char,char,char,char,char,car&car&lt&lts&lts&lts&lts&lts&lts&lts&lts&lts&lts&lts&lts&lts: &gt;&gt;,std :: __ cxx11 :: basic_string&lt; char,std :: char_traits&lt; char&gt;,std :: Allocator&lt; char&gt;&gt;&gt;const*,std :: vector&lt; std :: pair&lt&lt :: __ cxx11 :: basic_string&lt; char,std :: char_traits&lt; char&lt; char&lt; char&lt;&gt;,std :: __ cxx11 :: basic_string&lt; char,std :: char_traits&lt; char&gt;,std :: Allocator&lt; char&gt;&gt;&gt;,std ::分配器&lt; std :: pair&lt&lt :: __ __ cxx11 :: basic_string&lt; char,std :: char_traits&lt; char&lt; char&lt; std :: Aralocator&lt; char&gt;&gt;,std :: __ cxx11 :: basic_string&lt; char,std :: char_traits&lt; char&gt;,std :: Allocator&lt; char&gt;&gt;"&gt;,std :: __ cxx11 :: basic_string&lt; char,std :: char_traits&lt; char&gt;,std :: Allocator&lt; char&gt;&gt;&gt;*&gt;(__first = {first ="一个",second =" 1"},__last =
{first =&lt;错误读取变量:无法创建带有地址0x0的懒惰字符串,而不是零长度。
我使用clang
消毒剂来找出出了什么问题。只有内存消毒剂显示有趣的报告。跑步,
clang++ -std=c++17 -O1 -fsanitize=memory -fsanitize-memory-track-origins -fno-omit-frame-pointer main.cc
/a.out
报告,
通过'_znst4pairInst7__cxx1112basic_stringicst11chchar_traitsiceeesaiceees5_ec2ira6_kcra2_kcra2_kcra2_s8_lb1eeot_ot_ot_ot0_ot0_''s
通过" ref.tmp"的分配来创建非专业化值。
但是,当优化级别设置为-O3
时,什么都没有显示。
#include <algorithm>
#include <iostream>
#include <vector>
#include <experimental/string_view>
using Headers = std::vector<std::pair<std::string, std::string>>;
using string_view = std::experimental::string_view;
Headers::const_iterator find(Headers fields, const string_view field) {
if (field.empty()) return fields.cend();
//-----------------------------------
return
std::find_if(fields.cbegin(), fields.cend(), [field](const auto _) {
return std::equal(_.first.cbegin(), _.first.cend(), field.cbegin(), field.cend(),
[](const auto a, const auto b) { return std::tolower(a) == std::tolower(b); });
});
}
bool has_field(Headers fields, const string_view field)
{
return find(fields, field) != fields.cend();
}
int main()
{
Headers fields;
fields.emplace_back("one", "1");
fields.emplace_back("two", "2");
fields.emplace_back("three", "3");
fields.emplace_back("four", "4");
std::string s = "six";
if (has_field(fields, s))
std::cout << s << " is in " << "fields" << std::endl;
return 0;
}
可能是假阳性。LLVM带有符号器二进制文件,该象征器二进制允许消毒器输出线号。我设法以这个最小的示例来重现您的错误:
1 #include <iostream>
2 #include <vector>
3
4 using Headers = std::vector<int>;
5
6 bool a(Headers fields) {
7 return true;
8 }
9
10 bool b(Headers fields)
11 {
12 return a(fields);
13 }
14
15 int main()
16 {
17 Headers fields;
18
19 if (b(fields)) {
20 std::cout << std::endl;
21 }
22
23 return 0;
24 }
在这两种情况下,堆栈跟踪声称std::endl
是罪魁祸首。为了使错误发生以下魔术:
- 输出
std::endl
- 有两个函数调用
如果我将a
声明为fields
,则错误消失;b
不能说同样的话。所有这些都使我相信这是荒谬的,是假的。作为参考,这是带有行号的消毒剂输出:
Uninitialized bytes in __interceptor_memcmp at offset 192 inside [0x7fff18347610, 256)
==5724==WARNING: MemorySanitizer: use-of-uninitialized-value
#0 0x7f8f663d94ab in std::ctype<char>::_M_widen_init() const (/lib64/libstdc++.so.6+0xb74ab)
#1 0x7f8f66435d17 in std::basic_ostream<char, std::char_traits<char> >& std::endl<char, std::char_traits<char> >(std::basic_ostream<char, std::char_traits<char> >&) (/lib64/libstdc++.so.6+0x113d17)
#2 0x4912ff in main test.cpp:20:15
#3 0x7f8f65415889 in __libc_start_main (/lib64/libc.so.6+0x20889)
#4 0x41a9b9 in _start (a.out+0x41a9b9)
Uninitialized value was created by an allocation of 'ref.tmp' in the stack frame of function '_ZNSt6vectorIiSaIiEEC2ERKS1_'
#0 0x491360 in std::vector<int, std::allocator<int> >::vector(std::vector<int, std::allocator<int> > const&) /usr/bin/../lib/gcc/x86_64-redhat-linux/7/../../../../include/c++/7/bits/stl_vector.h:329
SUMMARY: MemorySanitizer: use-of-uninitialized-value (/lib64/libstdc++.so.6+0xb74ab) in std::ctype<char>::_M_widen_init() const
Exiting
看来,Clang的内存消毒器期望外部库(libtrdc )也可以进行仪器,否则可能是误报。
https://clang.llvm.org/docs/memorysanitizer.html#id11
"存储器"要求所有程序代码均已仪器。这还包括该程序依赖的任何库,甚至是libc。&quot"
因此,valgrind似乎仍然是非初始化值检测最实用的(尽管很慢)。
- 如何使用C++初始化向量;脚本化值不是数组、指针或矢量错误
- 内存清理程序报告全局对象构造中未初始化值的使用
- C++ - 空模板类构造函数不初始化值
- "co_yield"是否可以在恢复协程时从调用方返回值?
- C++序列生成器,按函数外壳具有初始化值
- 为什么未初始化的内存位置的值给出 -842150451 的值?
- 如何在C++中初始化值,然后稍后为uint32_t数组赋值
- 条件跳转或移动取决于 std::wistringstream 的未初始化值
- g++和g++14的未初始化值的差异
- 初始化值是否保证通过其自己的地址反映,而不考虑内存顺序
- 推荐的方法在不初始化值的情况下使数组类型为 std::unique_ptr?
- C++11默认初始化/值初始化/直接初始化
- 数组不保存初始化值
- 初始化原子指针是原子的吗?如果初始化或内存分配引发,会发生什么情况?
- 将类复制到未初始化的内存中是否安全?
- 从异类模板化值的容器返回模板化类型
- 编译时收到未初始化的内存警告
- clang 内存消毒剂报告使用非处方化值
- 正在通过内存集初始化值
- c++初始化动态内存中c样式字符串的默认值