Search code examples
c++googlemockcode-cleanup

How to properly cleanup after google mock objects when calling exit(0)?


According to https://learn.microsoft.com/en-us/cpp/cpp/program-termination?view=msvc-170#exit-function, "Issuing a return statement from the main function is equivalent to calling the exit function with the return value as its argument.".

Yet this proves to be wrong as the following example demonstrates:

main.cpp

#include "gtest/gtest.h"
#include "gmock/gmock.h"
 
#include "MyClass.h"  // defines a class named `MyClass`
#include "mock_test.h"
 
using ::testing::_;
using ::testing::Return;
 
int main(int argc, char **argv)
{
    Mock_MyClass mock_;
    EXPECT_CALL(mock_, foo(_))
        .WillRepeatedly(Return(0));
 
    exit(0);
}

mock_test.h

class Mock_MyClass : public MyClass
{
public:
    MOCK_METHOD(int, foo, (string& _), (override));
};

Assume that MyClass defines a virtual destructor and a method virtual int foo(string &) (yet the full content of MyClass is not relevant).

Upon running the program resulting from the preceding source code, I systematically get the following error:

ERROR: this mock object should be deleted but never is. Its address is @0000000001100EF0. ERROR: 1 leaked mock object found at program exit.

However, if exit(0) is replaced with return 0, I no longer get this error.

Hence it seems that calling exit(0) bypasses some cleanup process that happens when return 0 is used.

How can one, using exit(0), have the program cleanup after google mock objects in the same way that using return 0 would? That would enable one to terminate the program execution from a subfunction by calling exit(0) while ensuring to not get the above-mentioned error.

(I compiled for Linux, armv7, with -std=c++17)


Solution

  • That seems like an information specific to MSVC compiler only. cppreference on std::exit says:

    Stack is not unwound: destructors of variables with automatic storage duration are not called.

    For comparison, a moment later returning from main is mentioned:

    Returning from the main function, either by a return statement or by reaching the end of the function performs the normal function termination (calls the destructors of the variables with automatic storage durations) and then executes std::exit, passing the argument of the return statement (or ​0​ if implicit return was used) as exit_code.

    That is consistent with C++ standard support.start.term

    [...] (Objects with automatic storage duration are not destroyed as a result of calling exit().)

    So the only standard way to call those destructors is to

    • change object storage duration to static one (thread_local may work, I'm not sure) or
    • to use return instead of std::exit or
    • ensure destruction before std::exit call (e.g. by introducing another scope for the mock objects).