Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is it possible to recover from std::abort?

Our C codebase is using assert to check that preconditions/post conditions are being met.

#include <cstdlib>
#include <cassert>

void Aborting_Function(int n);

int main(){

    Aborting_Function(1); //good
    Aborting_Function(0); //calls std::abort()

    //Is it possible to recover somehow?
    //And continue on...
}

void Aborting_Function(int n){
    assert(n > 0);
    //impl...
}

In unit testing, I want to verify that functions are properly following their contracts
(aborting when they should).

Is it possible to recover from std::abort?

I realize it seems somewhat repetitive to have unit tests check exactly same thing that the assertions should be checking, but this would be helpful as we could automate the checking of particular use cases that should not work.

like image 329
Trevor Hickey Avatar asked Oct 27 '25 10:10

Trevor Hickey


2 Answers

Short answer, "no".

Rather than subverting abort(), you may want to consider using the google test framework.

This has the DEATH_TEST (documentation here: https://github.com/google/googletest/blob/master/googletest/docs/V1_7_AdvancedGuide.md)

Essentially what this does is fork a child process and checks whether the statement causes it to exit (which it would do if it aborted).

like image 185
Richard Hodges Avatar answered Oct 30 '25 00:10

Richard Hodges


For unit testing one can substitute abort() and longjmp() from there, or when testing via C++ throwing from there.

For example (expressed as C++):

#include <cassert>
#include <csetjmp>
#include <stdexcept>
#include <iostream>

#ifndef lest_ABORT_SIGNATURE
# if _MSC_VER
#  define lest_NORETURN  __declspec(noreturn)
#  define lest_ABORT_SIGNATURE()  _ACRTIMP lest_NORETURN void __cdecl abort(void)
# else
#  define lest_NORETURN  [[noreturn]]
#  define lest_ABORT_SIGNATURE()  lest_NORETURN void __cdecl abort()
# endif
#else
# ifndef  lest_NORETURN
#  define lest_NORETURN
# endif
#endif

#if USE_LONGJMP
    jmp_buf env;

    lest_ABORT_SIGNATURE()
    {
        std::longjmp( env, 1 );
    }
#else
    struct Abort{};

    lest_NORETURN void my_abort()
    {
        throw Abort{};
    }

    lest_ABORT_SIGNATURE()
    {
        // throw indirectly and prevent warning in VC14:
        my_abort();
    }
#endif

int main()
{
#if USE_LONGJMP
    if ( ! setjmp( env ) )
    {
        std::cout << "assert(false):\n";
        assert( false );
    }
    else
    {
        std::cout << "Intercepted abort\n";
    }
#else
    try
    {
        std::cout << "assert(false):\n";
        assert( false );
    }
    catch ( Abort const & )
    {
        std::cout << "Caught Abort\n";
    }
    catch ( std::exception const & e )
    {
        std::cout << "Exception: " << e.what() << "\n";
    }
#endif
    std::cout << "End\n";
}

#if 0
cl  -EHsc -DUSE_LONGJMP=1 abort-own.cpp && abort-own.exe
g++ -Wall -DUSE_LONGJMP=1 -std=c++11 -o abort-own.exe abort-own.cpp && abort-own.exe
#endif

Compiling with VC14 (VS2015) and runnning with:

cl -EHsc -DUSE_LONGJMP=1 abort-own.cpp && abort-own.exe

yields the following output:

...
assert(false):
Assertion failed: false, file abort-own.cpp, line 45
Intercepted abort
End

Compiling with a pre-VC14 compiler produces a link error:

LIBCMT.lib(abort.obj) : error LNK2005: _abort already defined in {file}
{exe} : fatal error LNK1169: one or more multiply defined symbols found

This may be cured by:

  • including /link /FORCE:MULTIPLE when compiling;
  • creating a runtime library with abort() removed.

Compiling via g++ using -std=c++03 or -std=c++11 does not lead to a multiply defined symbol.

More elaborate versions of the code above I'm developing for the lest test framework:

  • substitute abort(), longjmp(),
  • substitute abort(), throw
like image 28
Martin Moene Avatar answered Oct 30 '25 00:10

Martin Moene



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!