c++memory-sanitizer

Does `string s = std::to_string(1) + std::to_string(2)` use uninitialized memory


The question is, does the following snippet use uninitialized memory, as reported by Google's MemorySanitizer? Or is it a false positive?:

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

Result:

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

A mirror issue is also opened here


Solution

  • A mirror issue to this question received an answer. The gist of the answer is that MemorySanitizer is not a "plug-in"-style checker.

    To be specific, say we have a source code file main.cpp and we want to compile it to binary main.out, simply adding -fsanitize=memory -fsanitize-memory-track-origins to my compilation command is not enough. To avoid false positives, all the libraries used by main.out must also be compiled with -fsanitize=memory -fsanitize-memory-track-origins as well. In the answer, this is called "instrumentation".

    This official wiki post describes how we can achieve it.