[libcxx-commits] [libcxx] DRAFT [libc++][hardening] In production hardening modes, trap rather than abort (PR #78497)

Louis Dionne via libcxx-commits libcxx-commits at lists.llvm.org
Wed Jan 17 13:00:35 PST 2024


================
@@ -257,13 +275,20 @@ void std::__libcpp_verbose_abort(char const* format, ...) {
   std::exit(DeathTest::RK_Terminate);
 }
 
+enum class DeathCause {
+  VerboseAbort,
+  StdTerminate,
+  HardeningAssertion
+};
+
 template <class Func>
-inline bool ExpectDeath(const char* stmt, Func&& func, AssertionInfoMatcher Matcher) {
+inline bool ExpectDeath(DeathCause expected_cause, const char* stmt, Func&& func, AssertionInfoMatcher matcher) {
----------------
ldionne wrote:

I would suggest refactoring the code to something like:

```
enum ResultKind { RK_DidNotDie, RK_Terminate, RK_Trap, RK_VerboseAbort, RK_SetupFailure, RK_Unknown };
```

Then, the child process would:
1. Use a `std::terminate_handler` to exit with `RK_Terminate`
2. Override `__libcpp_verbose_abort` to exit with `RK_VerboseAbort` and print the message to stderr (but wouldn't do any matching)
3. Would return `RK_DidNotDie` otherwise (as it does)

The parent process would:
1. Check whether the child exited with a trap -- which the child process unfortunately can't signal
2. In case it terminated with `RK_VerboseAbort`, match on `stderr`.

Finally we could do something like

```c++
#if _LIBCPP_HARDENING_MODE == _LIBCPP_HARDENING_MODE_DEBUG
#  define TEST_LIBCPP_ASSERT_FAILURE(expr, message) assert(ExpectDeath(DeathTest::RK_VerboseAbort, ...))
#else
#  define TEST_LIBCPP_ASSERT_FAILURE(expr, message) assert(ExpectDeath(DeathTest::RK_Trap, ...))
#endif
```

That way you'd have a single enum kind representing all ways the child process can exit, and the error matching would be done in the parent (which IMO makes more sense -- it's always been weird to do it from the child).

https://github.com/llvm/llvm-project/pull/78497


More information about the libcxx-commits mailing list