Compiling with gcc-6 leads to segfaults in projects that use googletest,
because it invokes undefined behavior.
For example the yaml-cpp testsuite segfaults:
/var/tmp/yaml-cpp/test/gmock-1.7.0/include/gmock/gmock-spec-builders.h:1530:60: runtime error: member call on null pointer of type 'const struct ResultHolder'
[1] 20019 segmentation fault ./run-tests
"this" must never be NULL in C++.
Using "-fno-delete-null-pointer-checks" is a workaround.
1579 // Returns the result of invoking this mock function with the given
1580 // arguments. This function can be safely called from multiple
1581 // threads concurrently.
1582 Result InvokeWith(const ArgumentTuple& args)
1583 GTEST_LOCK_EXCLUDED_(g_gmock_mutex) {
1584 scoped_ptr<ResultHolder> holder(
1585 DownCast_<ResultHolder*>(this->UntypedInvokeWith(&args)));
1586 return holder->Unwrap();
1587 }
That snippet doesn't help me much. What ptr was null there?
Do you have more context for how a nullptr had a member function called on it?
markus@x4 test % gdb ./run-tests
Reading symbols from ./run-tests...done.
(gdb) b __ubsan::Diag::~Diag
(gdb) run
...
Breakpoint 1, 0x00007ffff6dfec40 in __ubsan::Diag::~Diag() () from /usr/lib/gcc/x86_64-pc-linux-gnu/6.0.0/libubsan.so.0
(gdb) bt
#0 0x00007ffff6dfec40 in __ubsan::Diag::~Diag() () from /usr/lib/gcc/x86_64-pc-linux-gnu/6.0.0/libubsan.so.0
#1 0x00007ffff6e02241 in handleTypeMismatchImpl(__ubsan::TypeMismatchData*, unsigned long, __ubsan::ReportOptions) ()
from /usr/lib/gcc/x86_64-pc-linux-gnu/6.0.0/libubsan.so.0
#2 0x00007ffff6e026d3 in __ubsan_handle_type_mismatch () from /usr/lib/gcc/x86_64-pc-linux-gnu/6.0.0/libubsan.so.0
#3 0x00000000005003dc in testing::internal::FunctionMockerBase<void (YAML::Mark const&)>::InvokeWith(std::tuple<YAML::Mark const&> const&) (
args=std::tuple containing = {...}, this=0x2842350) at /var/tmp/yaml-cpp/test/gmock-1.7.0/include/gmock/gmock-spec-builders.h:1530
#4 testing::internal::FunctionMocker<void (YAML::Mark const&)>::Invoke(YAML::Mark const&) (a1=..., this=0x2842350)
at /var/tmp/yaml-cpp/test/gmock-1.7.0/include/gmock/gmock-generated-function-mockers.h:97
#5 YAML::MockEventHandler::OnDocumentStart (this=<optimized out>, gmock_a1=...) at /var/tmp/yaml-cpp/test/mock_event_handler.h:10
#6 0x0000000001320f0f in YAML::SingleDocParser::HandleDocument (this=0x7fffffffda10, eventHandler=...) at /var/tmp/yaml-cpp/src/singledocparser.cpp:31
#7 0x00000000012686f5 in YAML::Parser::HandleNextDocument (this=this@entry=0x7fffffffdc50, eventHandler=...) at /var/tmp/yaml-cpp/src/parser.cpp:42
#8 0x00000000004f9717 in YAML::HandlerTest::Parse (
example="- |\n !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~\n- |\n 隆垄拢陇楼娄搂篓漏陋芦卢颅庐炉掳卤虏鲁麓碌露路赂鹿潞禄录陆戮驴脌脕脗脙脛脜脝脟脠脡脢脣脤脥", <
incomplete sequence \303>..., this=0x2842330) at /var/tmp/yaml-cpp/test/handler_test.h:17
#9 YAML::(anonymous namespace)::EncodingTest::Run (this=0x2842330) at /var/tmp/yaml-cpp/test/integration/encoding_test.cpp:105
#10 0x000000000145896b in testing::internal::HandleSehExceptionsInMethodIfSupported<testing::Test, void> (location=0x14b5616 "the test body", method=<optimized out>,
object=0x2842330) at /var/tmp/yaml-cpp/test/gmock-1.7.0/gtest/src/gtest.cc:2078
#11 testing::internal::HandleExceptionsInMethodIfSupported<testing::Test, void> (object=object@entry=0x2842330, method=<optimized out>,
location=location@entry=0x14b5616 "the test body") at /var/tmp/yaml-cpp/test/gmock-1.7.0/gtest/src/gtest.cc:2114
#12 0x00000000014226da in testing::Test::Run (this=this@entry=0x2842330) at /var/tmp/yaml-cpp/test/gmock-1.7.0/gtest/src/gtest.cc:2151
#13 0x00000000014231a3 in testing::Test::Run (this=0x2842330) at /var/tmp/yaml-cpp/test/gmock-1.7.0/gtest/src/gtest.cc:2142
#14 testing::TestInfo::Run (this=0x27fc3d0) at /var/tmp/yaml-cpp/test/gmock-1.7.0/gtest/src/gtest.cc:2326
#15 0x0000000001423de8 in testing::TestCase::Run (this=0x27fc4c0) at /var/tmp/yaml-cpp/test/gmock-1.7.0/gtest/src/gtest.cc:2444
#16 0x00000000014256ca in testing::internal::UnitTestImpl::RunAllTests (this=0x27f4d70) at /var/tmp/yaml-cpp/test/gmock-1.7.0/gtest/src/gtest.cc:4315
#17 0x0000000001459bcb in testing::internal::HandleSehExceptionsInMethodIfSupported<testing::internal::UnitTestImpl, bool> (
location=0x14ab870 "auxiliary test code (environments or event listeners)", method=<optimized out>, object=0x1424960 <testing::internal::UnitTestImpl::RunAllTests()>)
at /var/tmp/yaml-cpp/test/gmock-1.7.0/gtest/src/gtest.cc:2078
#18 testing::internal::HandleExceptionsInMethodIfSupported<testing::internal::UnitTestImpl, bool> (object=object@entry=0x27f4d70, method=<optimized out>,
location=location@entry=0x14ab870 "auxiliary test code (environments or event listeners)") at /var/tmp/yaml-cpp/test/gmock-1.7.0/gtest/src/gtest.cc:2114
#19 0x0000000001427519 in testing::UnitTest::Run (this=0x27e1a00 <testing::UnitTest::GetInstance()::instance>) at /var/tmp/yaml-cpp/test/gmock-1.7.0/gtest/src/gtest.cc:3926
#20 0x0000000000455f08 in RUN_ALL_TESTS () at /var/tmp/yaml-cpp/test/gmock-1.7.0/gtest/include/gtest/gtest.h:2288
#21 main (argc=<optimized out>, argv=<optimized out>) at /var/tmp/yaml-cpp/test/main.cpp:5
(gdb) up
#1 0x00007ffff6e02241 in handleTypeMismatchImpl(__ubsan::TypeMismatchData*, unsigned long, __ubsan::ReportOptions) ()
from /usr/lib/gcc/x86_64-pc-linux-gnu/6.0.0/libubsan.so.0
(gdb) up
#2 0x00007ffff6e026d3 in __ubsan_handle_type_mismatch () from /usr/lib/gcc/x86_64-pc-linux-gnu/6.0.0/libubsan.so.0
(gdb) up
#3 0x00000000005003dc in testing::internal::FunctionMockerBase<void (YAML::Mark const&)>::InvokeWith(std::tuple<YAML::Mark const&> const&) (
args=std::tuple containing = {...}, this=0x2842350) at /var/tmp/yaml-cpp/test/gmock-1.7.0/include/gmock/gmock-spec-builders.h:1530
1530 this->UntypedInvokeWith(&args))->GetValueAndDelete();
(gdb) l
1525 // arguments. This function can be safely called from multiple
1526 // threads concurrently.
1527 Result InvokeWith(const ArgumentTuple& args)
1528 GTEST_LOCK_EXCLUDED_(g_gmock_mutex) {
1529 return static_cast<const ResultHolder*>(
1530 this->UntypedInvokeWith(&args))->GetValueAndDelete();
1531 }
1532
1533 // Adds and returns a default action spec for this mock function.
1534 OnCallSpec<F>& AddNewOnCallSpec(
(gdb) p this
testing::internal::FunctionMockerBase<void(const YAML::Mark&)> * const) 0x2842350
(gdb) p *this
{
<testing::internal::UntypedFunctionMockerBase> = {
_vptr.UntypedFunctionMockerBase = 0x14c05a8 <vtable for testing::internal::FunctionMocker<void (YAML::Mark const&)>+16>,
mock_obj_ = 0x2842348,
name_ = 0x14ad1c7 "OnDocumentStart",
untyped_on_call_specs_ = std::vector of length 0, capacity 0,
untyped_expectations_ = std::vector of length 1, capacity 1 = {{
value_ = 0x283e390,
link_ = {
next_ = 0x283f588
}
}}
},
members of testing::internal::FunctionMockerBase<void(const YAML::Mark&)>:
current_spec_ = {
function_mocker_ = 0x2842350,
matchers_ = std::tuple containing = {
[1] = {
<testing::internal::MatcherBase<YAML::Mark const&>> = {
_vptr.MatcherBase = 0x14c0538 <vtable for testing::Matcher<YAML::Mark const&>+16>,
impl_ = {
value_ = 0x283d040,
link_ = {
next_ = 0x283e490
}
}
}, <No data fields>}
}
}
}
(gdb) p this->UntypedInvokeWith(&args)
$5 = (const testing::internal::UntypedActionResultHolderBase *) 0x0
Hi,
I also have the same issue with some valid unit test when using GCC 6.
Actually, this issue was fixed back in 2014, but the lack of GTest/GMock release since 2013 make us still hitting this issue... It was fixed in the trunk with b5c81098. This bug is only triggered when you try to mock a method returning void.
For those who don't want to use the trunk without a proper release, here is a patch that applies fine against GMock 1.7.0 which fixes this issue (without using -fno-delete-null-pointer-checks):
--- include/gmock/gmock-spec-builders.h
+++ include/gmock/gmock-spec-builders.h
@@ -1370,6 +1370,8 @@
template <>
class ActionResultHolder<void> : public UntypedActionResultHolderBase {
public:
+ explicit ActionResultHolder() {}
+
void GetValueAndDelete() const { delete this; }
virtual void PrintAsActionResult(::std::ostream* /* os */) const {}
@@ -1381,7 +1383,7 @@
const typename Function<F>::ArgumentTuple& args,
const string& call_description) {
func_mocker->PerformDefaultAction(args, call_description);
- return NULL;
+ return new ActionResultHolder();
}
// Performs the given action and returns NULL.
@@ -1390,7 +1392,7 @@
const Action<F>& action,
const typename Function<F>::ArgumentTuple& args) {
action.Perform(args);
- return NULL;
+ return new ActionResultHolder();
}
};
Cheers,
Romain
Most helpful comment
Hi,
I also have the same issue with some valid unit test when using GCC 6.
Actually, this issue was fixed back in 2014, but the lack of GTest/GMock release since 2013 make us still hitting this issue... It was fixed in the trunk with b5c81098. This bug is only triggered when you try to mock a method returning
void.For those who don't want to use the trunk without a proper release, here is a patch that applies fine against GMock 1.7.0 which fixes this issue (without using -fno-delete-null-pointer-checks):
Cheers,
Romain