Why valgrind reports “Uninitialised value” errors when running Google Test/Mock

Google Test is a C++ testing framework we’re using at Kullo. It creates a tiny binary that runs on a console and returns 0 or 1 depending on whether all tests succeeded or there was an error. So far so good.

Additionally we use valgrind to check for memory leaks, i.e. RAM that was allocated but not properly freed, which is an indication of programming errors.

You can do that by running your Google Test binary as follows:

valgrind --leak-check=full --error-exitcode=1 ./tests

Problem

One test resulted in a number of “Uninitialised value” errors, stating stuff like the following:

Use of uninitialised value of size 8
  at 0x677F9E1: _itoa_word (_itoa.c:180)
  by 0x67836D6: vfprintf (vfprintf.c:1641)
  by 0x683FC24: __vsnprintf_chk (vsnprintf_chk.c:63)
  by 0x683FB87: __snprintf_chk (snprintf_chk.c:34)
  by 0xA899B4: snprintf (stdio2.h:65)
  by 0xA899B4: testing::(anonymous namespace)::PrintByteSegmentInObjectTo(unsigned char const*, unsigned long, unsigned long, std::ostream*) (gtest-printers.cc:72)
  by 0xA8D1FC: PrintBytesInObjectToImpl (gtest-printers.cc:90)
  by 0xA8D1FC: testing::internal2::PrintBytesInObjectTo(unsigned char const*, unsigned long, std::ostream*) (gtest-printers.cc:112)

The test I am talking about looks something as simple as this one, where MyDao has an operator== and 17 member variables of different types.

TEST(MyDao_, equals)
{
    MyDao dao1();
    MyDao dao2();
    dao1.setId(123);
    dao2.setId(123);
    EXPECT_THAT(dao1, Eq(dao2));
}

It turned out that the size of MyDao was bigger than the size of its member variables (112 bytes vs. 106 bytes). This can be checked by comparing sizeof(X) for all member types and the object type.

On my platform (Linux 64 bit), GCC decided to add a padding to the object for performance reasons.

|                      MyDao (112 bytes)                      |
|-------------------------------------------------------------|
|----member1----|-member2-|##PADDING##|--------member3--------|

This padding area is recognized as uninitialized data from valgrind at the moment the data is accessed.

But who is accessing the data? From valgrind’s error message (that is at least a bit helpful when –track-origins=yes is set) it turned out that the Google Test printing function for arbitrary objects is running.

This printing function is there to make debugging possible in case a test did not pass (I made the test fail now), e.g.

Failure
Value of: dao1
Expected: is equal to 112-byte object <20-23 92-01 00-00 00-00 D0-07 92-01 00-00 00-00 00-00 00-00 01-00 00-00 7B-00 00-00 00-00 00-00 00-00 00-00 00-00 00-00 78-D6 5F-72 1F-7F 00-00 78-D6 5F-72 1F-7F 00-00 78-D6 5F-72 1F-7F 00-00 78-D6 5F-72 1F-7F 00-00 78-D6 5F-72 1F-7F 00-00 00-00 00-00 00-00 00-00 00-00 00-00 00-00 00-00 00-00 00-00 00-00 00-00 00-00 00-00 00-00 00-00>
Actual: 112-byte object <20-23 92-01 00-00 00-00 D0-07 92-01 00-00 00-00 00-00 00-00 01-00 00-00 7C-00 00-00 00-00 00-00 00-00 00-00 00-00 00-00 78-D6 5F-72 1F-7F 00-00 78-D6 5F-72 1F-7F 00-00 78-D6 5F-72 1F-7F 00-00 78-D6 5F-72 1F-7F 00-00 78-D6 5F-72 1F-7F 00-00 00-00 00-00 00-00 00-00 00-00 00-00 00-00 00-00 00-00 00-00 00-00 00-00 00-00 00-00 1F-7F 00-00> (of type MyDao)
[ FAILED ] MyDao.equals (125 ms)

As you can see, the whole object is accessed and printed, including the uninitialized padding.

I was able to add some unused member variables of type char to avoid padding and it turned out that valgrind stopped complaining about uninitialized data, but due to readability, maintainability and platform-dependent padding, this is not an option.

After all, this is expected behaviour, except for one thing: Why does Google Test run the printing function in a passing test? When MyDao::operator== returns true in that test, there is no need to print the objects.

Solution

You can add a custom printing function, i.e. add a function of the following signature that writes helpful debugging data about the state of MyDao to the output stream:

public:
    // ...

    friend std::ostream &operator<<(std::ostream &out, const MyDao &dao);

That will cause Google Test to use that function to print a custom type instead of accessing raw binary data, with the nice bonus that you now get more useful output in the case of a failing test.

1 thoughts on “Why valgrind reports “Uninitialised value” errors when running Google Test/Mock

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.