【发布时间】:2023-02-23 12:36:50
【问题描述】:
问题是,下面的 sn-p 是否使用了未初始化的内存,如 Google 的MemorySanitizer 所报告的那样?还是误报?:
-
main.cpp:
#include <string>
#include <iostream>
using namespace std;
int main() {
string s0 = to_string(1);
cout << "s0: " << s0 << endl;
string s1 = to_string(1) + to_string(2);
cout << "s1: " << s1 << endl;
return 0;
}
-
Makefile:
main:
clang++ -fsanitize=memory -fsanitize-memory-track-origins -fPIE -pie -fno-omit-frame-pointer -g -O2 main.cpp -o main-msan.out
clang++ -O2 main.cpp -o main.out
结果:
./main-msan.out
s0: 1
==122092==WARNING: MemorySanitizer: use-of-uninitialized-value
#0 0x55a7354e5cf7 in std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > std::operator+<char, std::char_traits<char>, std::allocator<char> >(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >&&, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >&&) /usr/bin/../lib/gcc/x86_64-linux-gnu/10/../../../../include/c++/10/bits/basic_string.h:6123:34
#1 0x55a7354e5cf7 in main <my_directory>/msan/main.cpp:9:30
#2 0x7f201f6edd09 in __libc_start_main csu/../csu/libc-start.c:308:16
#3 0x55a735468349 in _start (<my_directory>/msan/main-msan.out+0x21349)
Uninitialized value was created by an allocation of 'ref.tmp' in the stack frame of function 'main'
#0 0x55a7354e4d90 in main <my_directory>/msan/main.cpp:6
SUMMARY: MemorySanitizer: use-of-uninitialized-value /usr/bin/../lib/gcc/x86_64-linux-gnu/10/../../../../include/c++/10/bits/basic_string.h:6123:34 in std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > std::operator+<char, std::char_traits<char>, std::allocator<char> >(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >&&, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >&&)
Exiting
镜像问题也开here
【问题讨论】:
-
这是完全有效的代码。标准库实现可能会采用优化技术来阻止消毒剂。但这并不自动意味着实施有问题。它可能就像忘记在库代码中应用注释一样简单,以便消毒程序忽略“问题”。
-
有针对这种短字符串的短字符串优化。我不确定它是如何在 GCC 中实现的。但是有些字节没有在字符串中初始化是不合理的,因为它们的大小 <= 2,然后复制可能会解决这些未初始化的值。
-
@ALX23z 实际上我尝试了更长的时间,比如
string s1 = to_string(111) + to_string(222);,它仍然会触发投诉。同样为了让 MemorySanitizer 工作,我必须使用clang++。 -
@StoryTeller-UnslanderMonica 这是我在想的另一点。假设我有以下内容:
uint32_t a, b; uint32_t c = a + b; cout << c << endl;我的理解是这段代码是有效的,它不会调用任何 UB,因为unsigned int永远不会溢出。诚然,c的值可以是实现定义的或不确定的——但如果不知何故,如果我只需要一个值,但不关心值是什么,它应该可以正常工作。 -
由于这是 C++,因此相关部分是 timsong-cpp.github.io/cppwp/n4868/basic.indet#2 - 它适用于所有类型(
unsigned char或std::byte除外),当对存在 UB 作出笼统声明时。我不记得 C 标准究竟在哪里说过,但我记得在 C11 中看到过这种效果的措辞。
标签: c++ memory-sanitizer