Unable to reproduce memory sanitization results from the project's example project
Asked Answered
B

2

6

I'm getting exactly the same results from centos7, clang-3.6.1 built from source using a fedora rpm specfile. Ubuntu 14.04, clang-3.4

Using the instructions from the wiki here https://github.com/google/sanitizers/wiki/MemorySanitizerLibcxxHowTo as closely as possible. The page was last updated 6 months ago.

googlest revision 613 is still using tr1

In file included from /home/hal/googletest/src/gtest-all.cc:39:
In file included from /home/hal/googletest/include/gtest/gtest.h:58:
In file included from /home/hal/googletest/include/gtest/internal/gtest-internal.h:40:
/home/hal/googletest/include/gtest/internal/gtest-port.h:507:13: fatal error: 
      'tr1/tuple' file not found
#   include <tr1/tuple>  // NOLINT
            ^
1 error generated.

update googletest to tip (746) and it compiles with the following warning

➜ [hal@davis 9:54 ~/gtest-msan] make
Scanning dependencies of target gtest
[ 50%] Building CXX object CMakeFiles/gtest.dir/src/gtest-all.cc.o
clang: warning: -lc++abi: 'linker' input unused
clang: warning: -lc++abi: 'linker' input unused
clang: warning: argument unused during compilation: '-L/home/hal/libcxx_msan/lib'
clang: warning: argument unused during compilation: '-L/home/hal/libcxx_msan/lib'
Linking CXX static library libgtest.a

And the trivial suggested case from that page didn't get picked up by msan

[==========] Running 1 test from 1 test case.
[----------] Global test environment set-up.
[----------] 1 test from FooTest
[ RUN      ] FooTest.Foo
test.cc:7: Failure
Value of: foo[4]
  Actual: '\0'
Expected: 'z'
Which is: 'z' (122, 0x7A)
[  FAILED  ] FooTest.Foo (1 ms)
[----------] 1 test from FooTest (1 ms total)

[----------] Global test environment tear-down
[==========] 1 test from 1 test case ran. (1 ms total)
[  PASSED  ] 0 tests.
[  FAILED  ] 1 test, listed below:
[  FAILED  ] FooTest.Foo

 1 FAILED TEST

I have a project where valgrind barfs due to using some very large mmaps so memory sanitization would be really useful. If I'm doing something wrong. It appears that googletest suppresses the error somehow. Removing google test and converting the test case to

if(foo[4] == 'z') std::cout << "it is z" << std::endl;

Triggers the reporting of the obvious error as expected

==29128== WARNING: MemorySanitizer: use-of-uninitialized-value
    #0 0x7f59270c1738 in std::string::_Rep::_M_is_leaked() const /usr/lib/gcc/x86_64-redhat-linux/4.8.5/../../../../include/c++/4.8.5/bits/basic_string.h:192:18
    #1 0x7f59270c1738 in std::string::_M_leak() /usr/lib/gcc/x86_64-redhat-linux/4.8.5/../../../../include/c++/4.8.5/bits/basic_string.h:316
    #2 0x7f59270c1738 in std::string::operator[](unsigned long) /usr/lib/gcc/x86_64-redhat-linux/4.8.5/../../../../include/c++/4.8.5/bits/basic_string.h:849
    #3 0x7f59270c1738 in main /home/hal/test-gtest-msan/test2.cc:7
    #4 0x7f5925c2bb14 in __libc_start_main (/lib64/libc.so.6+0x21b14)
    #5 0x7f592706ce30 in _start (/home/hal/test-gtest-msan/test2+0x35e30)

  Uninitialized value was created by an allocation of 'foo' in the stack frame of function 'main'
    #0 0x7f59270c12e0 in main /home/hal/test-gtest-msan/test2.cc:4

SUMMARY: MemorySanitizer: use-of-uninitialized-value /usr/lib/gcc/x86_64-redhat-linux/4.8.5/../../../../include/c++/4.8.5/bits/basic_string.h:192 std::string::_Rep::_M_is_leaked() const
Exiting

Is it possible to use memory sanitization with a unit test library?

Baton answered 7/1, 2016 at 23:46 Comment(2)
Maybe you should rewrite your question to start from the beginning.Bowerbird
It literally does start from the beginning and provides every step. Thanks anyway.Baton
H
3

It's not MemorySanitizer or googletest problem: apparently libc++ has changed recently, and now it initializes bytes outside of the actual four-byte string "foo", so MSan is not producing the report for this out-of-bound access.

MSan wiki has been updated to use a different example, for which the error is reported as expected:

TEST(FooTest, Foo) {
  int uninitialized;
  EXPECT_GT(uninitialized, 5);
}

results in:

[==========] Running 1 test from 1 test case.
[----------] Global test environment set-up.
[----------] 1 test from FooTest
[ RUN      ] FooTest.Foo
==39032== WARNING: MemorySanitizer: use-of-uninitialized-value
    #0 0x48d73c in testing::AssertionResult testing::internal::CmpHelperGT<int, int>(char const*, char const*, int const&, int const&) googletest/include/gtest/gtest.h:1463:1
    #1 0x48ce7a in FooTest_Foo_Test::TestBody() test.cc:6:3
...

P.S. You can add -DGTEST_USE_OWN_TR1_TUPLE=1 to compile flags when you configure googletest to build it at revision 613.

Hackney answered 29/1, 2016 at 22:24 Comment(0)
D
0

Since the value seen in your unit test is '\0' it could be that the string actually initialized the the memory at position 4 to be compatible with a C-string (trailing zero). The difference between the unit test and your manual test case could be the result of compiler optimizations. What happens if you switch the string to a std::vector<char>{'f', 'o', 'o'}?

It would be helpful if you could post the unit test code too.

Dollarfish answered 19/1, 2016 at 19:21 Comment(3)
Unit test code from the provided link github.com/google/sanitizers/wiki/MemorySanitizerLibcxxHowTo with no changes.Baton
Changing std::string to std::vector<char> yielded exactly the same test output, reading foo[4] was ignored by the sanitizer.Baton
@Baton - "... reading foo[4] was ignored by the sanitizer..." - the optimizer may have changed it such that its no longer a simple read that you would expect to be flagged.Faubion

© 2022 - 2024 — McMap. All rights reserved.