2

On cygwin, EXPECT_CALL gives segmentation fault. Back trace shows:

Program received signal SIGSEGV, Segmentation fault.
0x004538e2 in join (ptr=0x61230494 <vtable for pthread_key+12>,
    this=0x8003aedc) at ./gtest/include/gtest/internal/gtest-linked_ptr.h:113
113         while (p->next_ != ptr) p = p->next_;
(gdb) bt
#0  0x004538e2 in join (ptr=0x61230494 <vtable for pthread_key+12>,
    this=0x8003aedc) at ./gtest/include/gtest/internal/gtest-linked_ptr.h:113
#1  copy<testing::internal::ExpectationBase> (
    ptr=0x61230490 <vtable for pthread_key+8>, this=0x8003aed8)
    at ./gtest/include/gtest/internal/gtest-linked_ptr.h:206
#2  linked_ptr (ptr=..., this=0x8003aed8)
    at ./gtest/include/gtest/internal/gtest-linked_ptr.h:149
#3  Expectation (this=0x8003aed8) at ./include/gmock/gmock-spec-builders.h:487
...
(gdb) p ptr
$1 = (const testing::internal::linked_ptr_internal *) 0x61230494 <vtable for pthread_key+12>
(gdb) p p
$2 = (const testing::internal::linked_ptr_internal *) 0x18ec8353
(gdb) p p->next_
Cannot access memory at address 0x18ec8353

Looks like some gmock internal link list corruption, but wired because my test is not that complex:

class to mock:

class NSEBase {
public:
    NSEBase(const std::string& ip, const std::string& port)
        : ip_(ip), port_(port) { } ;

    void setRequestHandler(RequestHandler& req_hdl) {
        request_handler_ = &req_hdl;
    };

    virtual void send(Response& rsp) { };
    virtual void run() { };

    virtual ~NSEBase() { };

private:
    RequestHandler * request_handler_;
    const std::string & ip_, port_;
};

Mock class header:

class NSEBaseMock : public NSEBase {
public:
  NSEBaseMock(const char* ip, const char* port) : NSEBase(ip, port) {};
  MOCK_METHOD0(run, void());
  MOCK_METHOD1(send, void(Response& rsp));
};

Mock class body:

class NSEBaseMockTest : public ::testing::Test {
protected:
    static const std::string retrieve_json;
    Request * req_;
    Response * rsp_;
    CSEBase * cse_;
    NSEBaseMock * nse_;
    CSEHandler * hdl_;
    CSEServer * server_;

public:
    virtual void SetUp()
    {
        ....
        nse_ = new NiceMock<NSEBaseMock>("127.0.0.1", "1234");
        ....  
        // cout shows it got here correctly
    }

    virtual void TearDown()
    {
        ....
        delete nse_;
        ....
    }

    void handleRequest() {
        req_ = new Request(retrieve_json);
        hdl_->handleRequest(*req_);
    }

};

const string NSEBaseMockTest::retrieve_json(....);

TEST_F(NSEBaseMockTest, RetrieveCSE) {

  EXPECT_CALL(*nse_, run()) **<--- crash here. no matter with .WillOnce or w/o.**
      .WillOnce(Invoke(this, &NSEBaseMockTest::handleRequest));

  std::cout << "EXPECT_CALL() done" << std::endl;

  ON_CALL(*nse_, send(Property(&Response::getResponseStatusCode, Eq(RSC_OK))));

  std::cout << "ON_CALL() done" << std::endl;


  server_->run();

}

Search through the gmock forum and here, no clue yet. I'm using all the latest up to today.

Shine me some ideas please:) Thanks.

Ray


Sorry Ian for late reply. here is my compile log, same flag for all cc files:

*g++ utest/gmock/NSEBase_mock.cc -Wall -D_WIN32_WINNT=0x0501 -D__USE_W32_SOCKETS -std=gnu++11 -Iinclude -Isrc -Istore -Isrc-gen -Icse -Iutest/gtest -I/cygdrive/c/Workspace/gmock-1.7.0/gtest/include -Iutest/gmock -I/cygdrive/c/Workspace/gmock-1.7.0/include -I/cygdrive/c/Workspace/gmock-1.7.0/gtest/include -g -c  -o build/utest/gmock/NSEBase_mock.o*

link command:

*`g++ build/src/Request.o build/src/RequestHandler.o build/src/Response.o build/src/CSEBase.o build/store/FakeStore.o build/src-gen/Response.pb.o build/src-gen/CSEBase.pb.o build/src-gen/CommonTypes.pb.o build/src-gen/Request.pb.o build/cse/CSEServer.o build/cse/CSEHandler.o build/utest/gmock/NSEBase_mock.o build/utest/gmock/gmock_main.o -ljson2pb -ljansson -lprotobuf -lpthread  -lboost_iostreams -lboost_filesystem -lboost_system -L/usr/local/lib  -lgtest -L/cygdrive/c/Workspace/gmock-1.7.0/gtest/lib/.libs -lgmock  -lgtest -L/cygdrive/c/Workspace/gmock-1.7.0/lib/.libs -L/cygdrive/c/Workspace/gmock-1.7.0/gtest/lib/.libs -lws2_32 -o build/gmock.exe`*

Regarding the ip_, port_ string reference in NSEBase, you are right, but it's not relevant yet, NSEBase is a stub right now, it still crashes.

Complete crash call trace:

Program received signal SIGSEGV, Segmentation fault.
0x00465002 in join (ptr=0x61230494 <vtable for pthread_key+12>,
    this=0x8003e844) at ./gtest/include/gtest/internal/gtest-linked_ptr.h:113
113         while (p->next_ != ptr) p = p->next_;
(gdb) bt
#0  0x00465002 in join (ptr=0x61230494 <vtable for pthread_key+12>,
    this=0x8003e844) at ./gtest/include/gtest/internal/gtest-linked_ptr.h:113
#1  copy<testing::internal::ExpectationBase> (
    ptr=0x61230490 <vtable for pthread_key+8>, this=0x8003e840)
    at ./gtest/include/gtest/internal/gtest-linked_ptr.h:206
#2  linked_ptr (ptr=..., this=0x8003e840)
    at ./gtest/include/gtest/internal/gtest-linked_ptr.h:149
#3  Expectation (this=0x8003e840) at ./include/gmock/gmock-spec-builders.h:487
#4  construct (this=<optimized out>, __val=..., __p=0x8003e840)
    at /usr/lib/gcc/i686-pc-cygwin/4.9.3/include/c++/ext/new_allocator.h:130
#5  _M_create_node (this=<optimized out>, __x=...)
    at /usr/lib/gcc/i686-pc-cygwin/4.9.3/include/c++/bits/stl_tree.h:397
#6  _M_insert_ (__v=..., __p=0x8003e498, __x=0x0, this=0x8003e494)
    at /usr/lib/gcc/i686-pc-cygwin/4.9.3/include/c++/bits/stl_tree.h:1143
#7  std::_Rb_tree<testing::Expectation, testing::Expectation, std::_Identity<testing::Expectation>, testing::Expectation::Less, std::allocator<testing::Expectation> >::_M_insert_unique (this=0x8003e494, __v=...)
    at /usr/lib/gcc/i686-pc-cygwin/4.9.3/include/c++/bits/stl_tree.h:1503
#8  0x00437bd0 in insert (__x=..., this=<optimized out>)
    at /usr/lib/gcc/i686-pc-cygwin/4.9.3/include/c++/bits/stl_set.h:502
#9  operator+= (e=..., this=<optimized out>)
    at ./include/gmock/gmock-spec-builders.h:602
#10 testing::Sequence::AddExpectation (this=0x8003af20, expectation=...)
    at ./src/gmock-spec-builders.cc:788
#11 0x00449511 in testing::internal::FunctionMockerBase<void ()>::AddNewExpectation(char const*, int, std::string const&, std::tuple<> const&) (
    this=0x8003e188,
    file=0x481bba <testing::_+104> "utest/gmock/NSEBase_mock.cc", line=74,
    source_text=..., m=...)
    at /cygdrive/c/Workspace/gmock-1.7.0/include/gmock/../../../gmock/include/gmock/../../../gmock/include/gmock/gmock-spec-builders.h:1560
#12 0x0044cf12 in testing::internal::MockSpec<void ()>::InternalExpectedAt(char const*, int, char const*, char const*) (this=0x8003e1ac,
    file=0x481bba <testing::_+104> "utest/gmock/NSEBase_mock.cc", line=74,
    obj=0x481bb4 <testing::_+98> "*nse_",
    call=0x481bae <testing::_+92> "run()")
    at /cygdrive/c/Workspace/gmock-1.7.0/include/gmock/../../../gmock/include/gmock/../../../gmock/include/gmock/gmock-spec-builders.h:1273
#13 0x0041432a in NSEBaseMockTest_RetrieveCSE_Test::TestBody (this=0x8003dd70)
    at utest/gmock/NSEBase_mock.cc:74
#14 0x0044c45c in HandleSehExceptionsInMethodIfSupported<testing::Test, void> (
    location=0x484c00 <(anonymous namespace)::b64_decode(std::string const&)::lookup+8000> "the test body",
    method=&virtual table offset 16, this adjustment -2147230352,
---Type <return> to continue, or q <return> to quit---
    object=0x8003dd70) at ./src/gtest.cc:2078
#15 testing::internal::HandleExceptionsInMethodIfSupported<testing::Test, void>
    (object=object@entry=0x8003dd70,
    method=(void (testing::Test::*)(testing::Test * const)) 0x4142c8 <NSEBaseMockTest_RetrieveCSE_Test::TestBody()>, this adjustment -2147230352,
    location=location@entry=0x484c00 <(anonymous namespace)::b64_decode(std::string const&)::lookup+8000> "the test body") at ./src/gtest.cc:2114
#16 0x0042fb59 in testing::Test::Run (this=0x8003dd70) at ./src/gtest.cc:2151
#17 0x0042fd18 in testing::TestInfo::Run (this=0x8003ac78)
    at ./src/gtest.cc:2326
#18 0x0042fe57 in Run (this=<optimized out>) at ./src/gtest.cc:2301
#19 testing::TestCase::Run (this=0x8003b508) at ./src/gtest.cc:2444
#20 0x00430325 in Run (this=<optimized out>) at ./src/gtest.cc:2430
#21 testing::internal::UnitTestImpl::RunAllTests (this=0x8003b330)
    at ./src/gtest.cc:4315
#22 0x0044c15c in HandleSehExceptionsInMethodIfSupported<testing::internal::UnitTestImpl, bool> (
    location=0x484d60 <(anonymous namespace)::b64_decode(std::string const&)::lookup+8352> "auxiliary test code (environments or event listeners)",
    method=(bool (testing::internal::UnitTestImpl::*)(testing::internal::UnitTestImpl * const)) 0x42ff60 <testing::internal::UnitTestImpl::RunAllTests()>, this adjustment -2147241168, object=0x8003b330) at ./src/gtest.cc:2078
#23 testing::internal::HandleExceptionsInMethodIfSupported<testing::internal::UnitTestImpl, bool> (object=0x8003b330,
    method=(bool (testing::internal::UnitTestImpl::*)(testing::internal::UnitTestImpl * const)) 0x42ff60 <testing::internal::UnitTestImpl::RunAllTests()>, this adjustment -2147241168,
    location=location@entry=0x484d60 <(anonymous namespace)::b64_decode(std::string const&)::lookup+8352> "auxiliary test code (environments or event listeners)") at ./src/gtest.cc:2114
#24 0x00430597 in testing::UnitTest::Run (
    this=0x4c81c8 <testing::UnitTest::GetInstance()::instance>)
    at ./src/gtest.cc:3929
#25 0x0043d793 in RUN_ALL_TESTS ()
    at /cygdrive/c/Workspace/gmock-1.7.0/include/gmock/../../../gmock/include/gmock/../../../gmock/include/gmock/internal/../../../../gmock/fused-src/gtest/gtest.h:20058
#26 0x004145c1 in main (argc=1, argv=0x28cc6c) at utest/gmock/gmock_main.cc:60

11 to #13 seems to add expectation to gmock internal structure, where link list got trouble.


Now simplify into one source file to make things clear.

gmtest.cc

#include "gmock/gmock.h"
#include "gtest/gtest.h"

class Base {
public:
    virtual void f1() { };
    virtual void f2() { };
};

class BaseMock : public Base {
public:
    MOCK_METHOD0(f1, void());
    MOCK_METHOD0(f2, void());
};

class BaseMockTest : public ::testing::Test {
};

TEST_F(BaseMockTest, Test1) {
    BaseMock bm;

    EXPECT_CALL(bm, f1()).Times(1);

    std::cout << "EXPECT_CALL done.\n";
}

GTEST_API_ int main(int argc, char** argv) {
  std::cout << "Running main() from gmock_main.cc\n";
  testing::InitGoogleMock(&argc, argv);
  return RUN_ALL_TESTS();
}

And compile link:

$ g++ -I/mnt/Workspace/gmock/include -I/mnt/Workspace/gmock/gtest/include -g -c gmtest.cc

$ g++ gmtest.o -L/mnt/Workspace/gmock/lib/.libs/ -lgmock -L/mnt/Workspace/gmock/gtest/lib/.libs -lgtest -o gmtest

Bom! Still crash! Can anybody verify this?

Ray

273K
  • 29,503
  • 10
  • 41
  • 64
Ray Xu
  • 51
  • 2
  • 6
  • Crashes in gmock are often mysterious... Couple of questions: (1) how are you compiling and linking in gmock symbols? If you're not using consistent compiler settings then weird crashes will often result. Also, not sure if this is related, but in NSEBase you're storing hard references to std::string, but when constructing the NSEBaseMock you're passing in temporary values. This means that the references to ip_ and port_ will not be valid after the constructor returns. – Ian Jul 27 '15 at 21:35
  • A couple of things: (1) you need to look at the compiler flags used to compile the *gmock* sources as well as your own sources. They have to be compatible for this to work. (2) if this *is* in fact a compiler flag problem, -std=gnu++11 is probably the most likely candidate. If the gmock library that your linking against wasn't compiled with -std=gnu++11, then all bets are off in terms of compatibility. – Ian Jul 30 '15 at 00:30
  • Some update. Same code works on Ubuntu well. I recompiled gmock and gtest within it with -std=gnu++11 on cygwin, unfortunately same thing - crash. Have to find alternatives. – Ray Xu Jul 31 '15 at 02:50

2 Answers2

3

Got the solution. Maybe Ian is right, still compile flag inconsistency issue between my code and Gmock. So use the fused gmock source code instead of libs, and the problem is gone. Generate fused gmock code:

scripts/python fuse_gmock_files.py OUTPUT_DIR

and pull it into your project, then don't forget to modify build setting to remove gmock/gtest libs.

Ray Xu
  • 51
  • 2
  • 6
0

I'm having the exact same issues, and indeed it was incompatible compiler flags. I've got a cmake 2.8 / CentOS 6.8 project that I need to compile under cmake 3.6 / Cygwin 2.9 for Windows 10 execution. I compiled both gtest and my project with VERBOSE turned on and compared the flags in use. I then added add_definitions( -DGTEST_HAS_PTHREAD=1 ) to my cmake project and have no issues with my unit tests that use gtest & gmock.

PfunnyGuy
  • 750
  • 9
  • 22