GMock, GCC 5.2 and the sanitizers

884 views
Skip to first unread message

Matt Godbolt

unread,
Aug 27, 2015, 5:41:58 PM8/27/15
to Google C++ Mocking Framework
Hi all,

I've been using GoogleMock & GoogleTest for many years, and have come to love it.

I'm in the process of moving our company's codebase to GCC 5.2 (from 4.9.2). All compiles and runs perfectly, but if I use the latest sanitizers (-fsanitize=address and/or -fsanitize=undefined), things start to go wrong in GMock.  We ran fine with GCC 4.9.2 with these flags, but that of course doesn't necessarily prove anything :)

The failures in our code base are complex, so I tried to winnow it to a small repro case. I was only partially able to do so, and so one thing I found I note here

First up, I got the latest code from github, and modified the Makefile in googlemock/make to point at GCC 5.2. All built and ran fine (yay). Then adding -fsanitize=address to CPPFLAGS shows this issue:

----

$ make
/home/mgodbolt/.fighome/runtime/gcc/5.2.0-1/bin/g++ -isystem ../../googletest//include -isystem ../include -Wl,-rpath,/home/mgodbolt/.fighome/runtime/gcc/5.2.0-1/lib64 -fsanitize=address -g -Wall -Wextra -pthread -c ../test/gmock_test.cc
/home/mgodbolt/.fighome/runtime/gcc/5.2.0-1/bin/g++ -isystem ../../googletest//include -isystem ../include -Wl,-rpath,/home/mgodbolt/.fighome/runtime/gcc/5.2.0-1/lib64 -fsanitize=address -I../../googletest/ -I.. -g -Wall -Wextra -pthread \
            -c ../src/gmock-all.cc
/home/mgodbolt/.fighome/runtime/gcc/5.2.0-1/bin/g++ -isystem ../../googletest//include -isystem ../include -Wl,-rpath,/home/mgodbolt/.fighome/runtime/gcc/5.2.0-1/lib64 -fsanitize=address -I../../googletest/ -I.. -g -Wall -Wextra -pthread \
            -c ../../googletest//src/gtest-all.cc
/home/mgodbolt/.fighome/runtime/gcc/5.2.0-1/bin/g++ -isystem ../../googletest//include -isystem ../include -Wl,-rpath,/home/mgodbolt/.fighome/runtime/gcc/5.2.0-1/lib64 -fsanitize=address -I../../googletest/ -I.. -g -Wall -Wextra -pthread \
            -c ../src/gmock_main.cc
ar rv gmock_main.a gmock-all.o gtest-all.o gmock_main.o
ar: creating gmock_main.a
a - gmock-all.o
a - gtest-all.o
a - gmock_main.o
/home/mgodbolt/.fighome/runtime/gcc/5.2.0-1/bin/g++ -isystem ../../googletest//include -isystem ../include -Wl,-rpath,/home/mgodbolt/.fighome/runtime/gcc/5.2.0-1/lib64 -fsanitize=address -g -Wall -Wextra -pthread -lpthread gmock_test.o gmock_main.a -o gmock_test
$ ./gmock_test 
Running main() from gmock_main.cc
[==========] Running 11 tests from 3 test cases.
[----------] Global test environment set-up.
[----------] 5 tests from InitGoogleMockTest
[ RUN      ] InitGoogleMockTest.ParsesInvalidCommandLine
[       OK ] InitGoogleMockTest.ParsesInvalidCommandLine (0 ms)
[ RUN      ] InitGoogleMockTest.ParsesEmptyCommandLine
[       OK ] InitGoogleMockTest.ParsesEmptyCommandLine (0 ms)
[ RUN      ] InitGoogleMockTest.ParsesSingleFlag
=================================================================
==58143==ERROR: AddressSanitizer: stack-buffer-overflow on address 0x7ffcd885b578 at pc 0x00000041f1e4 bp 0x7ffcd885b230 sp 0x7ffcd885b228
READ of size 8 at 0x7ffcd885b578 thread T0
    #0 0x41f1e3 in void testing::internal::InitGoogleMockImpl<char>(int*, char**) (/home/mgodbolt/dev/googletest/googlemock/make/gmock_test+0x41f1e3)
    #1 0x4170da in testing::InitGoogleMock(int*, char**) ../src/gmock.cc:174
    #2 0x40a0fd in void TestInitGoogleMock<char, 3, 2>(char const* (&) [3], char const* (&) [2], std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&) (/home/mgodbolt/dev/googletest/googlemock/make/gmock_test+0x40a0fd)
    #3 0x406f5b in InitGoogleMockTest_ParsesSingleFlag_Test::TestBody() ../test/gmock_test.cc:104
    #4 0x465730 in void testing::internal::HandleSehExceptionsInMethodIfSupported<testing::Test, void>(testing::Test*, void (testing::Test::*)(), char const*) ../../googletest/src/gtest.cc:2402
    #5 0x45bb47 in void testing::internal::HandleExceptionsInMethodIfSupported<testing::Test, void>(testing::Test*, void (testing::Test::*)(), char const*) ../../googletest/src/gtest.cc:2438
    #6 0x435115 in testing::Test::Run() ../../googletest/src/gtest.cc:2475
    #7 0x435e3f in testing::TestInfo::Run() ../../googletest/src/gtest.cc:2656
    #8 0x436747 in testing::TestCase::Run() ../../googletest/src/gtest.cc:2774
    #9 0x440748 in testing::internal::UnitTestImpl::RunAllTests() ../../googletest/src/gtest.cc:4647
    #10 0x467a22 in bool testing::internal::HandleSehExceptionsInMethodIfSupported<testing::internal::UnitTestImpl, bool>(testing::internal::UnitTestImpl*, bool (testing::internal::UnitTestImpl::*)(), char const*) ../../googletest/src/gtest.cc:2402
    #11 0x45d22b in bool testing::internal::HandleExceptionsInMethodIfSupported<testing::internal::UnitTestImpl, bool>(testing::internal::UnitTestImpl*, bool (testing::internal::UnitTestImpl::*)(), char const*) ../../googletest/src/gtest.cc:2438
    #12 0x43e420 in testing::UnitTest::Run() ../../googletest/src/gtest.cc:4255
    #13 0x478937 in RUN_ALL_TESTS() ../../googletest//include/gtest/gtest.h:2237
    #14 0x478893 in main ../src/gmock_main.cc:53
    #15 0x7f46d3575ec4 in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x21ec4)
    #16 0x406b28  (/home/mgodbolt/dev/googletest/googlemock/make/gmock_test+0x406b28)

Address 0x7ffcd885b578 is located in stack of thread T0 at offset 120 in frame
    #0 0x406e65 in InitGoogleMockTest_ParsesSingleFlag_Test::TestBody() ../test/gmock_test.cc:92

  This frame has 2 object(s):
    [32, 48) 'new_argv'
    [96, 120) 'argv' <== Memory access at offset 120 overflows this variable
HINT: this may be a false positive if your program uses some custom stack unwind mechanism or swapcontext
      (longjmp and C++ exceptions *are* supported)
SUMMARY: AddressSanitizer: stack-buffer-overflow ??:0 void testing::internal::InitGoogleMockImpl<char>(int*, char**)
Shadow bytes around the buggy address:
  0x10001b103650: 00 00 00 00 f3 f3 f3 f3 00 00 00 00 00 00 00 00
  0x10001b103660: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x10001b103670: 00 00 00 00 f1 f1 f1 f1 04 f4 f4 f4 f2 f2 f2 f2
  0x10001b103680: 00 00 f4 f4 f2 f2 f2 f2 00 00 00 00 f3 f3 f3 f3
  0x10001b103690: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
=>0x10001b1036a0: f1 f1 f1 f1 00 00 f4 f4 f2 f2 f2 f2 00 00 00[f4]
  0x10001b1036b0: f3 f3 f3 f3 00 00 00 00 00 00 00 00 00 00 00 00
  0x10001b1036c0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x10001b1036d0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x10001b1036e0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x10001b1036f0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
Shadow byte legend (one shadow byte represents 8 application bytes):
  Addressable:           00
  Partially addressable: 01 02 03 04 05 06 07 
  Heap left redzone:       fa
  Heap right redzone:      fb
  Freed heap region:       fd
  Stack left redzone:      f1
  Stack mid redzone:       f2
  Stack right redzone:     f3
  Stack partial redzone:   f4
  Stack after return:      f5
  Stack use after scope:   f8
  Global redzone:          f9
  Global init order:       f6
  Poisoned by user:        f7
  Container overflow:      fc
  Array cookie:            ac
  Intra object redzone:    bb
  ASan internal:           fe
==58143==ABORTING

----

The failure we saw in our codebase (which uses the release 1.7.0 version; *not* the github head, in case that's relevant) seems to be related to -fsanitize=undefined. I've been unable to get a repro case, but I'll describe what I saw in case anyone has any ideas: upon calls to mock methods without expectations, I see a crash in FunctionMockerBase::InvokeWith:
include/gmock/gmock-spec-builders.h:1530:60: runtime error: member call on null pointer of type 'const struct ResultHolder'
ASAN:SIGSEGV
=================================================================
==43330==ERROR: AddressSanitizer: SEGV on unknown address 0x000000000000 (pc 0x00000067a90c bp 0x7ffc86243550 sp 0x7ffc862434f0 T0)
    #0 0x67a90b in testing::internal::FunctionMockerBase<void (std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, ExternalIocOms<int>::Order const&, int&)>::InvokeWith(std::tuple<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, ExternalIocOms<int>::Order const&, int&> const&) include/gmock/gmock-spec-builders.h:1530
    #1 0x67a90b in testing::internal::FunctionMocker<void (std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, ExternalIocOms<int>::Order const&, int&)>::Invoke(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, ExternalIocOms<int>::Order const&, int&) include/gmock/gmock-generated-function-mockers.h:162
    #2 0x67a90b in onNew test/lbm/ExternalIocOmsTest.cpp:21

this crash goes away if I take out the "undefined" sanitizer, which could either point the finger at a GCC sanitizer bug, or perhaps there's a change buried somewhere in the diffs between 1.7.0 and git head that I haven't spotted (lots of things moved around...).

Any ideas or thoughts on either of these issues welcomed.

Much obliged,
Matt

Samuel Benzaquen

unread,
Aug 27, 2015, 6:10:41 PM8/27/15
to Matt Godbolt, Google C++ Mocking Framework
This is a bug in the test. Thanks for the report.
Apparently our ASan coverage didn't include this specific test.
I'll get it fixed.
 
----

The failure we saw in our codebase (which uses the release 1.7.0 version; *not* the github head, in case that's relevant) seems to be related to -fsanitize=undefined. I've been unable to get a repro case, but I'll describe what I saw in case anyone has any ideas: upon calls to mock methods without expectations, I see a crash in FunctionMockerBase::InvokeWith:
include/gmock/gmock-spec-builders.h:1530:60: runtime error: member call on null pointer of type 'const struct ResultHolder'
ASAN:SIGSEGV
=================================================================
==43330==ERROR: AddressSanitizer: SEGV on unknown address 0x000000000000 (pc 0x00000067a90c bp 0x7ffc86243550 sp 0x7ffc862434f0 T0)
    #0 0x67a90b in testing::internal::FunctionMockerBase<void (std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, ExternalIocOms<int>::Order const&, int&)>::InvokeWith(std::tuple<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, ExternalIocOms<int>::Order const&, int&> const&) include/gmock/gmock-spec-builders.h:1530
    #1 0x67a90b in testing::internal::FunctionMocker<void (std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, ExternalIocOms<int>::Order const&, int&)>::Invoke(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, ExternalIocOms<int>::Order const&, int&) include/gmock/gmock-generated-function-mockers.h:162
    #2 0x67a90b in onNew test/lbm/ExternalIocOmsTest.cpp:21

this crash goes away if I take out the "undefined" sanitizer, which could either point the finger at a GCC sanitizer bug, or perhaps there's a change buried somewhere in the diffs between 1.7.0 and git head that I haven't spotted (lots of things moved around...).

I could not reproduce this one.
Maybe it is somehow related to the code in ExternmallocOmsTest.cpp?
Sorry, not enough context.
 

Any ideas or thoughts on either of these issues welcomed.

Much obliged,
Matt

--

---
You received this message because you are subscribed to the Google Groups "Google C++ Mocking Framework" group.
To unsubscribe from this group and stop receiving emails from it, send an email to googlemock+...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/googlemock/91705be2-0672-4440-9d30-467bad6c5c6c%40googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Matt Godbolt

unread,
Aug 28, 2015, 10:19:16 AM8/28/15
to Samuel Benzaquen, Google C++ Mocking Framework
On Thu, Aug 27, 2015 at 5:10 PM, Samuel Benzaquen <sbe...@google.com> wrote:
==58143==ABORTING


This is a bug in the test. Thanks for the report.
Apparently our ASan coverage didn't include this specific test.
I'll get it fixed.

Fab: thanks!
 
 
...this crash goes away if I take out the "undefined" sanitizer, which could either point the finger at a GCC sanitizer bug, or perhaps there's a change buried somewhere in the diffs between 1.7.0 and git head that I haven't spotted (lots of things moved around...).

I could not reproduce this one.
Maybe it is somehow related to the code in ExternmallocOmsTest.cpp?
Sorry, not enough context.

Understood, thanks. I don't believe it to be somethign specific to our code as pretty much any mock usage in our tests caused the same crash. I'll dig into this more on our side and see if I discover how we're misuing gmock incorrectly, or have some other bad compiler flags, else I'll try and whittle it to a reproducible test here.

Thanks for the reply!

Matt :)

Matt Godbolt

unread,
Aug 28, 2015, 12:21:35 PM8/28/15
to Samuel Benzaquen, Google C++ Mocking Framework
Hi again,

I've been able to reproduce this by checking out the 1.7.0 branch. If one checks out 1.7.0 (from the deprecated GoogleMock repo), and then modifies the make/Makefile to point at GCC 5.2 and a 1.7.0 GoogleTest checkout, this simple test reproduces my problem:

struct Foo { virtual ~Foo() {}; virtual void bar() = 0; };

struct MockFoo : Foo {
        MOCK_METHOD0(bar, void());
    };

TEST(Mock, shouldDoNothing) {
    MockFoo foo;
    foo.bar();
}

---
~/d/g/googlemock ((release-1.7.0)) $ git diff Makefile
diff --git a/make/Makefile b/make/Makefile
index 9ac7449..b05372b 100644
--- a/make/Makefile
+++ b/make/Makefile
@@ -25,7 +25,17 @@ USER_DIR = ../samples
 CPPFLAGS += -isystem $(GTEST_DIR)/include
 
 # Flags passed to the C++ compiler.
-CXXFLAGS += -g -Wall -Wextra -pthread
+CXXFLAGS += -g -Wall -Wextra -pthread \
+  -Wl,-rpath,/home/mgodbolt/.fighome/runtime/gcc/5.2.0-1/lib64 \
+  -fsanitize=address -fsanitize=undefined
+
+CXX=/home/mgodbolt/.fighome/runtime/gcc/5.2.0-1/bin/g++
~/d/g/googlemock ((release-1.7.0)) $ make
/home/mgodbolt/.fighome/runtime/gcc/5.2.0-1/bin/g++ -isystem ../../googletest/include -isystem ../include -g -Wall -Wextra -pthread -Wl,-rpath,/home/mgodbolt/.fighome/runtime/gcc/5.2.0-1/lib64 -fsanitize=address -fsanitize=undefined -c ../test/gmock_test.cc
/home/mgodbolt/.fighome/runtime/gcc/5.2.0-1/bin/g++ -isystem ../../googletest/include -isystem ../include -g -Wall -Wextra -pthread -Wl,-rpath,/home/mgodbolt/.fighome/runtime/gcc/5.2.0-1/lib64 -fsanitize=address -fsanitize=undefined -lpthread gmock_test.o gmock_main.a -o gmock_test
~/d/g/make ((release-1.7.0)) $ ./gmock_test 
Running main() from gmock_main.cc
[==========] Running 1 test from 1 test case.
[----------] Global test environment set-up.
[----------] 1 test from Mock
[ RUN      ] Mock.shouldDoNothing

GMOCK WARNING:
Uninteresting mock function call - returning directly.
    Function call: bar()
Stack trace:
../include/gmock/gmock-spec-builders.h:1530:60: runtime error: member call on null pointer of type 'const struct ResultHolder'
../include/gmock/gmock-spec-builders.h:1530:60: runtime error: member access within null pointer of type 'const struct ResultHolder'
ASAN:SIGSEGV
=================================================================
==89125==ERROR: AddressSanitizer: SEGV on unknown address 0x000000000000 (pc 0x00000040c41d bp 0x7ffc94da67d0 sp 0x7ffc94da67b0 T0)
    #0 0x40c41c in testing::internal::FunctionMockerBase<void ()>::InvokeWith(std::tr1::tuple<> const&) (/home/mgodbolt/dev/googlemock/make/gmock_test+0x40c41c)
    #1 0x40b892 in testing::internal::FunctionMocker<void ()>::Invoke() (/home/mgodbolt/dev/googlemock/make/gmock_test+0x40b892)
    #2 0x40afe0 in MockFoo::bar() (/home/mgodbolt/dev/googlemock/make/gmock_test+0x40afe0)
    #3 0x407d4d in Mock_shouldDoNothing_Test::TestBody() ../test/gmock_test.cc:53
    #4 0x4ce7b1 in void testing::internal::HandleSehExceptionsInMethodIfSupported<testing::Test, void>(testing::Test*, void (testing::Test::*)(), char const*) ../../googletest/src/gtest.cc:2078
    #5 0x4be5ce in void testing::internal::HandleExceptionsInMethodIfSupported<testing::Test, void>(testing::Test*, void (testing::Test::*)(), char const*) ../../googletest/src/gtest.cc:2114
    #6 0x466ac5 in testing::Test::Run() ../../googletest/src/gtest.cc:2151
    #7 0x468d26 in testing::TestInfo::Run() ../../googletest/src/gtest.cc:2326
    #8 0x46ac3d in testing::TestCase::Run() ../../googletest/src/gtest.cc:2444
    #9 0x488ce1 in testing::internal::UnitTestImpl::RunAllTests() ../../googletest/src/gtest.cc:4315
    #10 0x4d2efb in bool testing::internal::HandleSehExceptionsInMethodIfSupported<testing::internal::UnitTestImpl, bool>(testing::internal::UnitTestImpl*, bool (testing::internal::UnitTestImpl::*)(), char const*) ../../googletest/src/gtest.cc:2078
    #11 0x4c1a92 in bool testing::internal::HandleExceptionsInMethodIfSupported<testing::internal::UnitTestImpl, bool>(testing::internal::UnitTestImpl*, bool (testing::internal::UnitTestImpl::*)(), char const*) ../../googletest/src/gtest.cc:2114
    #12 0x4800e9 in testing::UnitTest::Run() ../../googletest/src/gtest.cc:3926
    #13 0x4eb6ba in RUN_ALL_TESTS() ../../googletest/include/gtest/gtest.h:2288
    #14 0x4eb531 in main ../src/gmock_main.cc:53
    #15 0x7fe426aa3ec4 in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x21ec4)
    #16 0x407b68  (/home/mgodbolt/dev/googlemock/make/gmock_test+0x407b68)

AddressSanitizer can not provide additional info.
SUMMARY: AddressSanitizer: SEGV ??:0 testing::internal::FunctionMockerBase<void ()>::InvokeWith(std::tr1::tuple<> const&)
==89125==ABORTING

----

I can dig further, but this issue has seemingly been fixed in the head git revision. I couldn't see an obvious commit that might have fixed this, does anyone have any thoughts?

Also; are there any plans to make a new version of GoogleTest available? It seems there's been a good lot of changes (certainly at least combining gmock and gtest, which is a great thing) - it would be great to use the latest version.

Thanks, Matt
--
Matt
Reply all
Reply to author
Forward
0 new messages