catchorg / catchorg/Catch2

Using `REQUIRE` in a destructor breaks tests

Open
#2,655 2 comments 0 reactions 0 assignees View on GitHub
Not a bug Resolved - pending review
Dominant language
C++
Stars
21.5k
Forks
3.5k
Avg merge
3d 16h
Merged PRs (30d)
2

Description

**Describe the bug**

This example (where the destructor of an object during unwind has a failing `CHECK`) works gracefully:

```cpp
#include

struct Guard {
~Guard() {
CHECK(3 == 4);
}
};

TEST_CASE("throwing into check") {
Guard g;
throw std::runtime_error("hi");
}
```

I get output like:

```
-------------------------------------------------------------------------------
throwing into check
-------------------------------------------------------------------------------
catch-throw.cxx:9
...............................................................................

catch-throw.cxx:5: FAILED:
CHECK( 3 == 4 )

catch-throw.cxx:5: FAILED:
{Unknown expression after the reported line}
due to unexpected exception with message:
hi
```

But this version (changing the `CHECK` for a `REQUIRE`):

```cpp
#include

struct Guard {
~Guard() {
REQUIRE(3 == 4);
}
};

TEST_CASE("throwing into require") {
Guard g;
throw std::runtime_error("hi");
}
```

explodes:

```
-------------------------------------------------------------------------------
throwing into require
-------------------------------------------------------------------------------
catch-throw.cxx:9
...............................................................................

catch-throw.cxx:5: FAILED:
REQUIRE( 3 == 4 )

terminate called after throwing an instance of 'Catch::TestFailureException'
catch-throw.cxx:5: FAILED:
{Unknown expression after the reported line}
due to a fatal error condition:
SIGABRT - Abort (abnormal termination) signal

===============================================================================
test cases: 1 | 1 failed
assertions: 2 | 2 failed
```

**Expected behavior**

I'd expect the `CHECK` and `REQUIRE` cases to behave similarly. In this case the test is already halting due to the throw, so it should not halt even harder. Replace the `throw` with a _passing_ `CHECK`, and the test still aborts, rather than gracefully failing.

**Reproduction steps**

The above are two complete test cases. Just compile and run (linking against both `libCatch2.a` and `libCatch2Main.a`

**Platform information:**

Catch 3.3.1.

This was using gcc 11 C++17 with the old ABI (`-D_GLIBCXX_USE_CXX11_ABI=0`).

Contributor guide

Open the contributing guide

Research direction

Start by compiling and running the two complete reproductions using the Catch test macros, linked against libCatch2.a and libCatch2Main.a, with the reported GCC 11/C++17 settings. Compare CHECK and REQUIRE during destructor unwinding; done means the REQUIRE case no longer aborts unexpectedly and behaves consistently with the CHECK case.

Written by the indexing model from the issue text.

Assessment

Tech stack
cpp
Domain
testing
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Stale
Clarity
Clearly specified
Newbie friendliness
38/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.