[libcxx-commits] [libcxx] [libc++][hardening] In production hardening modes, trap rather than abort (PR #78561)
Konstantin Varlamov via libcxx-commits
libcxx-commits at lists.llvm.org
Fri Jan 19 12:04:05 PST 2024
https://github.com/var-const updated https://github.com/llvm/llvm-project/pull/78561
>From 9308d0520ea99f806682b62b1659f4c327da1ca6 Mon Sep 17 00:00:00 2001
From: Konstantin Varlamov <varconsteq at gmail.com>
Date: Thu, 18 Jan 2024 02:38:55 -0800
Subject: [PATCH 01/11] [libc++][hardening] In production hardening modes, trap
instead of abort
TODO
---
...tomize_verbose_abort.compile-time.pass.cpp | 1 +
...customize_verbose_abort.link-time.pass.cpp | 1 +
.../assertions/default_verbose_abort.pass.cpp | 1 +
libcxx/test/support/check_assertion.h | 401 ++++++++++++------
.../test_check_assertion.pass.cpp | 111 +++--
.../vendor/llvm/default_assertion_handler.in | 11 +-
6 files changed, 357 insertions(+), 169 deletions(-)
diff --git a/libcxx/test/libcxx/assertions/customize_verbose_abort.compile-time.pass.cpp b/libcxx/test/libcxx/assertions/customize_verbose_abort.compile-time.pass.cpp
index d09881e8cecb9f..d176d8a12875e6 100644
--- a/libcxx/test/libcxx/assertions/customize_verbose_abort.compile-time.pass.cpp
+++ b/libcxx/test/libcxx/assertions/customize_verbose_abort.compile-time.pass.cpp
@@ -8,6 +8,7 @@
// This compile-time customization requires cross-file macros, which doesn't work with modules.
// UNSUPPORTED: clang-modules-build
+// REQUIRES: libcpp-hardening-mode=debug
// Make sure that we can customize the verbose termination function at compile-time by
// defining _LIBCPP_VERBOSE_ABORT ourselves. Note that this does not have any
diff --git a/libcxx/test/libcxx/assertions/customize_verbose_abort.link-time.pass.cpp b/libcxx/test/libcxx/assertions/customize_verbose_abort.link-time.pass.cpp
index 219c43874e77db..c82aaea6ba30df 100644
--- a/libcxx/test/libcxx/assertions/customize_verbose_abort.link-time.pass.cpp
+++ b/libcxx/test/libcxx/assertions/customize_verbose_abort.link-time.pass.cpp
@@ -11,6 +11,7 @@
// We flag uses of the verbose termination function in older dylibs at compile-time to avoid runtime
// failures when back-deploying.
// XFAIL: availability-verbose_abort-missing
+// REQUIRES: libcpp-hardening-mode=debug
#include <cstdlib>
diff --git a/libcxx/test/libcxx/assertions/default_verbose_abort.pass.cpp b/libcxx/test/libcxx/assertions/default_verbose_abort.pass.cpp
index 870f43da4b8f02..29ef10016c1a37 100644
--- a/libcxx/test/libcxx/assertions/default_verbose_abort.pass.cpp
+++ b/libcxx/test/libcxx/assertions/default_verbose_abort.pass.cpp
@@ -7,6 +7,7 @@
//===----------------------------------------------------------------------===//
// Test that the default verbose termination function aborts the program.
+// REQUIRES: libcpp-hardening-mode=debug
#include <csignal>
#include <cstdlib>
diff --git a/libcxx/test/support/check_assertion.h b/libcxx/test/support/check_assertion.h
index 83a46548fa9250..8e1493b70a66a6 100644
--- a/libcxx/test/support/check_assertion.h
+++ b/libcxx/test/support/check_assertion.h
@@ -16,6 +16,7 @@
#include <cstdlib>
#include <exception>
#include <regex>
+#include <sstream>
#include <string>
#include <string_view>
#include <utility>
@@ -27,37 +28,70 @@
#include "test_allocator.h"
#if TEST_STD_VER < 11
-# error "C++11 or greater is required to use this header"
+# error "C++11 or greater is required to use this header"
#endif
struct AssertionInfoMatcher {
- static const int any_line = -1;
+ // When printing the assertion message to `stderr`, delimit it with a marker to make it easier to match the message
+ // later.
+ static constexpr const char* Marker = "###";
+
+ static const int any_line = -1;
static constexpr const char* any_file = "*";
- static constexpr const char* any_msg = "*";
+ static constexpr const char* any_msg = "*";
- constexpr AssertionInfoMatcher() : is_empty_(true), msg_(any_msg, __builtin_strlen(any_msg)), file_(any_file, __builtin_strlen(any_file)), line_(any_line) { }
+ constexpr AssertionInfoMatcher()
+ : msg_(any_msg, __builtin_strlen(any_msg)), file_(any_file, __builtin_strlen(any_file)), line_(any_line) {}
constexpr AssertionInfoMatcher(const char* msg, const char* file = any_file, int line = any_line)
- : is_empty_(false), msg_(msg, __builtin_strlen(msg)), file_(file, __builtin_strlen(file)), line_(line) {}
+ : is_empty_(false), msg_(msg, __builtin_strlen(msg)), file_(file, __builtin_strlen(file)), line_(line) {}
+
+ bool CheckMatchInOutput(const std::string& output, std::string& error) const {
+ // Extract information from the error message. This has to stay synchronized with how we format assertions in the
+ // library.
+ std::regex message_format(".*###\\n(.*):(\\d+): assertion (.*) failed: (.*)\\n###");
+
+ std::smatch match_result;
+ bool has_match = std::regex_match(output, match_result, message_format);
+ assert(has_match);
+ assert(match_result.size() == 5);
+
+ const std::string& file = match_result[1];
+ int line = std::stoi(match_result[2]);
+ // Omitting `expression` in `match_result[3]`
+ const std::string& failure_reason = match_result[4];
+
+ bool result = Matches(file, line, failure_reason);
+ if (!result) {
+ error = FormatMatchingError(file, line, failure_reason);
+ }
+ return result;
+ }
- bool Matches(char const* file, int line, char const* message) const {
- assert(!empty() && "empty matcher");
+ bool Matches(const std::string& file, int line, const std::string& message) const {
+ assert(!empty() && "Empty matcher");
+ return CheckLineMatches(line) && CheckFileMatches(file) && CheckMessageMatches(message);
+ }
- if (CheckLineMatches(line) && CheckFileMatches(file) && CheckMessageMatches(message))
- return true;
- // Write to stdout because that's the file descriptor captured by the parent
- // process.
- std::printf("Failed to match assertion info!\n%s\nVS\n%s:%d (%s)\n", ToString().data(), file, line, message);
- return false;
+ std::string FormatMatchingError(const std::string& file, int line, const std::string& message) const {
+ std::stringstream output;
+ output //
+ << "Expected message: '" << msg_.data() << "'\n" //
+ << "Actual message: '" << message.c_str() << "'\n" //
+ << "Expected location: " << FormatLocation(file_, line_) << "\n" //
+ << "Actual location: " << FormatLocation(file, line) << "\n";
+ return output.str();
}
- std::string ToString() const {
- std::string result = "msg = \""; result += msg_; result += "\"\n";
- result += "line = " + (line_ == any_line ? "'*'" : std::to_string(line_)) + "\n";
- result += "file = " + (file_ == any_file ? "'*'" : std::string(file_));
+ static std::string FormatLocation(std::string_view file, int line) {
+ std::string result;
+ result += (file == any_file ? "*" : std::string(file)) + ":";
+ result += (line == any_line ? "*" : std::to_string(line));
return result;
}
bool empty() const { return is_empty_; }
+ bool IsAnyMatcher() const { return msg_ == any_msg && file_ == any_file && line_ == any_line; }
+
private:
bool CheckLineMatches(int got_line) const {
if (line_ == any_line)
@@ -90,10 +124,13 @@ struct AssertionInfoMatcher {
std::size_t found_at = got_msg.find(msg_);
if (found_at == std::string_view::npos)
return false;
- return found_at == 0 && got_msg.size() == msg_.size();
+ // Allow any match
+ return true;
}
+
private:
- bool is_empty_;
+ bool is_empty_ = true;
+ ;
std::string_view msg_;
std::string_view file_;
int line_;
@@ -101,44 +138,175 @@ struct AssertionInfoMatcher {
static constexpr AssertionInfoMatcher AnyMatcher(AssertionInfoMatcher::any_msg);
-inline AssertionInfoMatcher& GlobalMatcher() {
- static AssertionInfoMatcher GMatch;
- return GMatch;
+enum class DeathCause {
+ // Valid causes
+ VerboseAbort = 1,
+ StdTerminate,
+ Trap,
+ // Invalid causes
+ DidNotDie,
+ SetupFailure,
+ Unknown
+};
+
+bool IsValidCause(DeathCause cause) {
+ switch (cause) {
+ case DeathCause::VerboseAbort:
+ case DeathCause::StdTerminate:
+ case DeathCause::Trap:
+ return true;
+ default:
+ return false;
+ }
}
-struct DeathTest {
- enum ResultKind {
- RK_DidNotDie, RK_MatchFound, RK_MatchFailure, RK_Terminate, RK_SetupFailure, RK_Unknown
- };
+std::string ToString(DeathCause cause) {
+ switch (cause) {
+ case DeathCause::VerboseAbort:
+ return "verbose abort";
+ case DeathCause::StdTerminate:
+ return "`std::terminate`";
+ case DeathCause::Trap:
+ return "trap";
+ case DeathCause::DidNotDie:
+ return "<invalid cause (did not die)>";
+ case DeathCause::SetupFailure:
+ return "<invalid cause (setup failure)>";
+ case DeathCause::Unknown:
+ return "<invalid cause (unknown)>";
+ }
+}
- static const char* ResultKindToString(ResultKind RK) {
-#define CASE(K) case K: return #K
- switch (RK) {
- CASE(RK_MatchFailure);
- CASE(RK_DidNotDie);
- CASE(RK_SetupFailure);
- CASE(RK_MatchFound);
- CASE(RK_Unknown);
- CASE(RK_Terminate);
- }
- return "not a result kind";
+TEST_NORETURN void StopChildProcess(DeathCause cause) { std::exit(static_cast<int>(cause)); }
+
+DeathCause ConvertToDeathCause(int val) {
+ if (val < static_cast<int>(DeathCause::VerboseAbort) || val > static_cast<int>(DeathCause::Unknown)) {
+ return DeathCause::Unknown;
}
+ return static_cast<DeathCause>(val);
+}
+
+enum class Outcome {
+ Success,
+ UnexpectedCause,
+ UnexpectedAbortMessage,
+ InvalidCause,
+};
- static bool IsValidResultKind(int val) {
- return val >= RK_DidNotDie && val <= RK_Unknown;
+std::string ToString(Outcome outcome) {
+ switch (outcome) {
+ case Outcome::Success:
+ return "success";
+ case Outcome::UnexpectedCause:
+ return "unexpected death cause";
+ case Outcome::UnexpectedAbortMessage:
+ return "unexpected verbose abort message";
+ case Outcome::InvalidCause:
+ return "invalid death cause";
}
+}
+
+class DeathTestResult {
+ public:
+ DeathTestResult() = default;
+ DeathTestResult(Outcome set_outcome, DeathCause set_cause, const std::string& set_failure_description = "")
+ : outcome_(set_outcome), cause_(set_cause), failure_description_(set_failure_description) {}
+
+ bool success() const { return outcome() == Outcome::Success; }
+ Outcome outcome() const { return outcome_; }
+ DeathCause cause() const { return cause_; }
+ const std::string& failure_description() const { return failure_description_; }
+
+ private:
+ Outcome outcome_ = Outcome::Success;
+ DeathCause cause_ = DeathCause::Unknown;
+ std::string failure_description_;
+};
- DeathTest(AssertionInfoMatcher const& Matcher) : matcher_(Matcher) {}
+class DeathTest {
+ public:
+ DeathTest() = default;
+ DeathTest(DeathTest const&) = delete;
+ DeathTest& operator=(DeathTest const&) = delete;
template <class Func>
- ResultKind Run(Func&& f) {
+ DeathTestResult Run(DeathCause expected_cause, Func&& func, const AssertionInfoMatcher& matcher) {
+ std::set_terminate([] {
+ StopChildProcess(DeathCause::StdTerminate);
+ });
+
+ DeathCause cause = Run(func);
+
+ auto DescribeDeathCauseMismatch = [](DeathCause expected, DeathCause actual) {
+ std::stringstream output;
+ output //
+ << "Child died, but with a different death cause\n" //
+ << "Expected cause: " << ToString(expected) << "\n" //
+ << "Actual cause: " << ToString(actual) << "\n";
+ return output.str();
+ };
+
+ switch (cause) {
+ case DeathCause::StdTerminate:
+ case DeathCause::Trap:
+ if (expected_cause != cause) {
+ auto failure_description = DescribeDeathCauseMismatch(expected_cause, cause);
+ return DeathTestResult(Outcome::UnexpectedCause, cause, failure_description);
+ }
+ return DeathTestResult(Outcome::Success, cause);
+
+ case DeathCause::VerboseAbort: {
+ if (expected_cause != cause) {
+ auto failure_description = DescribeDeathCauseMismatch(expected_cause, cause);
+ return DeathTestResult(Outcome::UnexpectedCause, cause, failure_description);
+ }
+
+ std::string maybe_error;
+ if (matcher.CheckMatchInOutput(getChildStdErr(), maybe_error)) {
+ return DeathTestResult(Outcome::Success, cause);
+ }
+ auto failure_description = std::string("Child died, but with a different verbose abort message\n") + maybe_error;
+ return DeathTestResult(Outcome::UnexpectedAbortMessage, cause, failure_description);
+ }
+
+ // Invalid causes.
+ case DeathCause::DidNotDie:
+ return DeathTestResult(Outcome::InvalidCause, cause, "Child did not die");
+ case DeathCause::SetupFailure:
+ return DeathTestResult(Outcome::InvalidCause, cause, "Child failed to set up test environment");
+ case DeathCause::Unknown:
+ return DeathTestResult(Outcome::InvalidCause, cause, "Cause unknown");
+ }
+
+ assert(false && "Unreachable");
+ }
+
+ void PrintFailureDetails(std::string_view failure_description, std::string_view stmt, DeathCause cause) const {
+ std::fprintf(
+ stderr, "Failure: EXPECT_DEATH( %s ) failed!\n(reason: %s)\n\n", stmt.data(), failure_description.data());
+
+ if (cause != DeathCause::Unknown) {
+ std::fprintf(stderr, "child exit code: %d\n", getChildExitCode());
+ }
+ std::fprintf(stderr, "---------- standard err ----------\n%s", getChildStdErr().c_str());
+ std::fprintf(stderr, "\n----------------------------------\n");
+ std::fprintf(stderr, "---------- standard out ----------\n%s", getChildStdOut().c_str());
+ std::fprintf(stderr, "\n----------------------------------\n");
+ };
+
+ int getChildExitCode() const { return exit_code_; }
+ std::string const& getChildStdOut() const { return stdout_from_child_; }
+ std::string const& getChildStdErr() const { return stderr_from_child_; }
+
+private:
+ template <class Func>
+ DeathCause Run(Func&& f) {
int pipe_res = pipe(stdout_pipe_fd_);
assert(pipe_res != -1 && "failed to create pipe");
pipe_res = pipe(stderr_pipe_fd_);
assert(pipe_res != -1 && "failed to create pipe");
pid_t child_pid = fork();
- assert(child_pid != -1 &&
- "failed to fork a process to perform a death test");
+ assert(child_pid != -1 && "failed to fork a process to perform a death test");
child_pid_ = child_pid;
if (child_pid_ == 0) {
RunForChild(std::forward<Func>(f));
@@ -147,10 +315,6 @@ struct DeathTest {
return RunForParent();
}
- int getChildExitCode() const { return exit_code_; }
- std::string const& getChildStdOut() const { return stdout_from_child_; }
- std::string const& getChildStdErr() const { return stderr_from_child_; }
-private:
template <class Func>
TEST_NORETURN void RunForChild(Func&& f) {
close(GetStdOutReadFD()); // don't need to read from the pipe in the child.
@@ -158,14 +322,13 @@ struct DeathTest {
auto DupFD = [](int DestFD, int TargetFD) {
int dup_result = dup2(DestFD, TargetFD);
if (dup_result == -1)
- std::exit(RK_SetupFailure);
+ StopChildProcess(DeathCause::SetupFailure);
};
DupFD(GetStdOutWriteFD(), STDOUT_FILENO);
DupFD(GetStdErrWriteFD(), STDERR_FILENO);
- GlobalMatcher() = matcher_;
f();
- std::exit(RK_DidNotDie);
+ StopChildProcess(DeathCause::DidNotDie);
}
static std::string ReadChildIOUntilEnd(int FD) {
@@ -190,7 +353,7 @@ struct DeathTest {
close(GetStdErrReadFD());
}
- ResultKind RunForParent() {
+ DeathCause RunForParent() {
CaptureIOFromChild();
int status_value;
@@ -199,35 +362,29 @@ struct DeathTest {
if (WIFEXITED(status_value)) {
exit_code_ = WEXITSTATUS(status_value);
- if (!IsValidResultKind(exit_code_))
- return RK_Unknown;
- return static_cast<ResultKind>(exit_code_);
+ return ConvertToDeathCause(exit_code_);
}
- return RK_Unknown;
- }
- DeathTest(DeathTest const&) = delete;
- DeathTest& operator=(DeathTest const&) = delete;
+ if (WIFSIGNALED(status_value)) {
+ exit_code_ = WTERMSIG(status_value);
+ if (exit_code_ == SIGILL || exit_code_ == SIGTRAP) {
+ return DeathCause::Trap;
+ }
+ }
- int GetStdOutReadFD() const {
- return stdout_pipe_fd_[0];
+ return DeathCause::Unknown;
}
- int GetStdOutWriteFD() const {
- return stdout_pipe_fd_[1];
- }
+ int GetStdOutReadFD() const { return stdout_pipe_fd_[0]; }
- int GetStdErrReadFD() const {
- return stderr_pipe_fd_[0];
- }
+ int GetStdOutWriteFD() const { return stdout_pipe_fd_[1]; }
+
+ int GetStdErrReadFD() const { return stderr_pipe_fd_[0]; }
+
+ int GetStdErrWriteFD() const { return stderr_pipe_fd_[1]; }
- int GetStdErrWriteFD() const {
- return stderr_pipe_fd_[1];
- }
-private:
- AssertionInfoMatcher matcher_;
pid_t child_pid_ = -1;
- int exit_code_ = -1;
+ int exit_code_ = -1;
int stdout_pipe_fd_[2];
int stderr_pipe_fd_[2];
std::string stdout_from_child_;
@@ -235,82 +392,56 @@ struct DeathTest {
};
#ifdef _LIBCPP_VERSION
-void std::__libcpp_verbose_abort(char const* printf_format, ...) {
- // Extract information from the error message. This has to stay synchronized with how we format assertions in the
- // library.
+void std::__libcpp_verbose_abort(char const* format, ...) {
va_list args;
- va_start(args, printf_format);
- char const* message = va_arg(args, char const*);
-
- std::regex message_format("(.*):(\\d+): assertion (.*) failed: (.*)\\n");
+ va_start(args, format);
- std::cmatch match_result;
- bool has_match = std::regex_match(message, match_result, message_format);
- assert(has_match);
- assert(match_result.size() == 5);
+ std::fprintf(stderr, "%s\n", AssertionInfoMatcher::Marker);
+ std::vfprintf(stderr, format, args);
+ std::fprintf(stderr, "%s", AssertionInfoMatcher::Marker);
- std::string file = match_result[1];
- int line = std::stoi(match_result[2]);
- // Omitting `expression` in `match_result[3]`
- std::string failure_reason = match_result[4];
+ va_end(args);
- if (GlobalMatcher().Matches(file.c_str(), line, failure_reason.c_str())) {
- std::exit(DeathTest::RK_MatchFound);
- }
- std::exit(DeathTest::RK_MatchFailure);
+ StopChildProcess(DeathCause::VerboseAbort);
}
#endif // _LIBCPP_VERSION
-[[noreturn]] inline void terminate_handler() {
- std::exit(DeathTest::RK_Terminate);
-}
-
template <class Func>
-inline bool ExpectDeath(const char* stmt, Func&& func, AssertionInfoMatcher Matcher) {
- std::set_terminate(terminate_handler);
- DeathTest DT(Matcher);
- DeathTest::ResultKind RK = DT.Run(func);
- auto OnFailure = [&](const char* msg) {
- std::fprintf(stderr, "EXPECT_DEATH( %s ) failed! (%s)\n\n", stmt, msg);
- if (RK != DeathTest::RK_Unknown) {
- std::fprintf(stderr, "child exit code: %d\n", DT.getChildExitCode());
- }
- if (!DT.getChildStdErr().empty()) {
- std::fprintf(stderr, "---------- standard err ----------\n%s\n", DT.getChildStdErr().c_str());
- }
- if (!DT.getChildStdOut().empty()) {
- std::fprintf(stderr, "---------- standard out ----------\n%s\n", DT.getChildStdOut().c_str());
- }
- return false;
- };
- switch (RK) {
- case DeathTest::RK_MatchFound:
- case DeathTest::RK_Terminate:
- return true;
- case DeathTest::RK_SetupFailure:
- return OnFailure("child failed to setup test environment");
- case DeathTest::RK_Unknown:
- return OnFailure("reason unknown");
- case DeathTest::RK_DidNotDie:
- return OnFailure("child did not die");
- case DeathTest::RK_MatchFailure:
- return OnFailure("matcher failed");
+inline bool ExpectDeath(DeathCause expected_cause, const char* stmt, Func&& func, AssertionInfoMatcher matcher) {
+ assert(IsValidCause(expected_cause));
+
+ DeathTest test_case;
+ DeathTestResult test_result = test_case.Run(expected_cause, func, matcher);
+ if (!test_result.success()) {
+ test_case.PrintFailureDetails(test_result.failure_description(), stmt, test_result.cause());
}
- assert(false && "unreachable");
+
+ return test_result.success();
}
template <class Func>
-inline bool ExpectDeath(const char* stmt, Func&& func) {
- return ExpectDeath(stmt, func, AnyMatcher);
+inline bool ExpectDeath(DeathCause expected_cause, const char* stmt, Func&& func) {
+ return ExpectDeath(expected_cause, stmt, func, AnyMatcher);
}
-/// Assert that the specified expression throws a libc++ debug exception.
-#define EXPECT_DEATH(...) assert((ExpectDeath(#__VA_ARGS__, [&]() { __VA_ARGS__; } )))
-
-#define EXPECT_STD_TERMINATE(...) assert(ExpectDeath(#__VA_ARGS__, __VA_ARGS__))
-
-#define EXPECT_DEATH_MATCHES(Matcher, ...) assert((ExpectDeath(#__VA_ARGS__, [&]() { __VA_ARGS__; }, Matcher)))
-
-#define TEST_LIBCPP_ASSERT_FAILURE(expr, message) assert((ExpectDeath(#expr, [&]() { (void)(expr); }, AssertionInfoMatcher(message))))
+// clang-format off
+
+/// Assert that the specified expression aborts with the expected cause and, optionally, error message.
+#define EXPECT_DEATH(...) \
+ assert(( ExpectDeath(DeathCause::VerboseAbort, #__VA_ARGS__, [&]() { __VA_ARGS__; } ) ))
+#define EXPECT_DEATH_MATCHES(matcher, ...) \
+ assert(( ExpectDeath(DeathCause::VerboseAbort, #__VA_ARGS__, [&]() { __VA_ARGS__; }, matcher) ))
+#define EXPECT_STD_TERMINATE(...) \
+ assert( ExpectDeath(DeathCause::StdTerminate, #__VA_ARGS__, __VA_ARGS__) )
+
+#if _LIBCPP_HARDENING_MODE == _LIBCPP_HARDENING_MODE_DEBUG
+#define TEST_LIBCPP_ASSERT_FAILURE(expr, message) \
+ assert(( ExpectDeath(DeathCause::VerboseAbort, #expr, [&]() { (void)(expr); }, AssertionInfoMatcher(message)) ))
+#else
+#define TEST_LIBCPP_ASSERT_FAILURE(expr, message) \
+ assert(( ExpectDeath(DeathCause::Trap, #expr, [&]() { (void)(expr); }) ))
+#endif // _LIBCPP_HARDENING_MODE == _LIBCPP_HARDENING_MODE_DEBUG
+
+// clang-format on
#endif // TEST_SUPPORT_CHECK_ASSERTION_H
diff --git a/libcxx/test/support/test.support/test_check_assertion.pass.cpp b/libcxx/test/support/test.support/test_check_assertion.pass.cpp
index 7cf0e0966ce89d..b45c101f567cda 100644
--- a/libcxx/test/support/test.support/test_check_assertion.pass.cpp
+++ b/libcxx/test/support/test.support/test_check_assertion.pass.cpp
@@ -18,47 +18,94 @@
#include "check_assertion.h"
template <class Func>
-inline bool TestDeathTest(const char* stmt, Func&& func, DeathTest::ResultKind ExpectResult, AssertionInfoMatcher Matcher = AnyMatcher) {
- DeathTest DT(Matcher);
- DeathTest::ResultKind RK = DT.Run(func);
- auto OnFailure = [&](std::string msg) {
- std::fprintf(stderr, "EXPECT_DEATH( %s ) failed! (%s)\n\n", stmt, msg.c_str());
- if (!DT.getChildStdErr().empty()) {
- std::fprintf(stderr, "---------- standard err ----------\n%s\n", DT.getChildStdErr().c_str());
- }
- if (!DT.getChildStdOut().empty()) {
- std::fprintf(stderr, "---------- standard out ----------\n%s\n", DT.getChildStdOut().c_str());
+inline bool TestDeathTest(
+ Outcome expected_outcome, DeathCause expected_cause, const char* stmt, Func&& func, AssertionInfoMatcher matcher) {
+ DeathTest test_case;
+ DeathTestResult test_result = test_case.Run(expected_cause, func, matcher);
+ std::string maybe_failure_description;
+
+ Outcome outcome = test_result.outcome();
+ if (expected_outcome != outcome) {
+ maybe_failure_description +=
+ std::string("Test outcome was different from expected; expected ") + ToString(expected_outcome) +
+ ", got: " + ToString(outcome);
+ }
+
+ DeathCause cause = test_result.cause();
+ if (expected_cause != cause) {
+ auto failure_description =
+ std::string("Cause of death was different from expected; expected ") + ToString(expected_cause) +
+ ", got: " + ToString(cause);
+ if (maybe_failure_description.empty()) {
+ maybe_failure_description = failure_description;
+ } else {
+ maybe_failure_description += std::string("; ") + failure_description;
}
+ }
+
+ if (!maybe_failure_description.empty()) {
+ test_case.PrintFailureDetails(maybe_failure_description, stmt, test_result.cause());
return false;
- };
- if (RK != ExpectResult)
- return OnFailure(std::string("expected result did not occur: expected ") + DeathTest::ResultKindToString(ExpectResult) + " got: " + DeathTest::ResultKindToString(RK));
+ }
+
return true;
}
-#define TEST_DEATH_TEST(RK, ...) assert((TestDeathTest(#__VA_ARGS__, [&]() { __VA_ARGS__; }, RK, AnyMatcher )))
-#define TEST_DEATH_TEST_MATCHES(RK, Matcher, ...) assert((TestDeathTest(#__VA_ARGS__, [&]() { __VA_ARGS__; }, RK, Matcher)))
+// clang-format off
-void my_libcpp_assert() {
- _LIBCPP_ASSERT(false, "other");
-}
+#define TEST_DEATH_TEST(outcome, cause, ...) \
+ assert(( TestDeathTest(outcome, cause, #__VA_ARGS__, [&]() { __VA_ARGS__; }, AnyMatcher) ))
+#define TEST_DEATH_TEST_MATCHES(outcome, cause, matcher, ...) \
+ assert(( TestDeathTest(outcome, cause, #__VA_ARGS__, [&]() { __VA_ARGS__; }, matcher) ))
-void test_no_match_found() {
- AssertionInfoMatcher ExpectMatch("my message");
- TEST_DEATH_TEST_MATCHES(DeathTest::RK_MatchFailure, ExpectMatch, my_libcpp_assert());
-}
+// clang-format on
-void test_did_not_die() {
- TEST_DEATH_TEST(DeathTest::RK_DidNotDie, ((void)0));
-}
+int main(int, char**) {
+ { // Success -- verbose abort with any matcher.
+ auto fail_assert = [] { _LIBCPP_ASSERT(false, "Some message"); };
+#if _LIBCPP_HARDENING_MODE == _LIBCPP_HARDENING_MODE_DEBUG
+ TEST_DEATH_TEST_MATCHES(Outcome::Success, DeathCause::VerboseAbort, AnyMatcher, fail_assert());
+#else
+ TEST_DEATH_TEST_MATCHES(Outcome::Success, DeathCause::Trap, AnyMatcher, fail_assert());
+#endif
+ }
-void test_unknown() {
- TEST_DEATH_TEST(DeathTest::RK_Unknown, std::exit(13));
-}
+ { // Success -- verbose abort with a specific matcher.
+ auto fail_assert = [] { _LIBCPP_ASSERT(false, "Some message"); };
+ AssertionInfoMatcher matcher("Some message");
+#if _LIBCPP_HARDENING_MODE == _LIBCPP_HARDENING_MODE_DEBUG
+ TEST_DEATH_TEST_MATCHES(Outcome::Success, DeathCause::VerboseAbort, matcher, fail_assert());
+#else
+ TEST_DEATH_TEST_MATCHES(Outcome::Success, DeathCause::Trap, matcher, fail_assert());
+#endif
+ }
+
+ { // Success -- `std::terminate`.
+ TEST_DEATH_TEST(Outcome::Success, DeathCause::StdTerminate, std::terminate());
+ }
+
+ { // Success -- trapping.
+ TEST_DEATH_TEST(Outcome::Success, DeathCause::Trap, __builtin_trap());
+ }
+
+ { // Error message doesn't match.
+ auto fail_assert = [] { _LIBCPP_ASSERT(false, "Actual message doesn't match"); };
+ AssertionInfoMatcher matcher("Bad expected message");
+#if _LIBCPP_HARDENING_MODE == _LIBCPP_HARDENING_MODE_DEBUG
+ TEST_DEATH_TEST_MATCHES(Outcome::UnexpectedAbortMessage, DeathCause::VerboseAbort, matcher, fail_assert());
+#else
+ TEST_DEATH_TEST_MATCHES(Outcome::Success, DeathCause::Trap, matcher, fail_assert());
+#endif
+ }
+
+
+ { // Invalid cause -- child did not die.
+ TEST_DEATH_TEST(Outcome::InvalidCause, DeathCause::DidNotDie, ((void)0));
+ }
+
+ { // Invalid cause -- unknown.
+ TEST_DEATH_TEST(Outcome::InvalidCause, DeathCause::Unknown, std::exit(13));
+ }
-int main(int, char**) {
- test_no_match_found();
- test_did_not_die();
- test_unknown();
return 0;
}
diff --git a/libcxx/vendor/llvm/default_assertion_handler.in b/libcxx/vendor/llvm/default_assertion_handler.in
index 111d305a16f7c4..60bbf27489097b 100644
--- a/libcxx/vendor/llvm/default_assertion_handler.in
+++ b/libcxx/vendor/llvm/default_assertion_handler.in
@@ -17,7 +17,14 @@
# pragma GCC system_header
#endif
-// TODO(hardening): in production, trap rather than abort.
-#define _LIBCPP_ASSERTION_HANDLER(message) _LIBCPP_VERBOSE_ABORT("%s", message)
+#if _LIBCPP_HARDENING_MODE == _LIBCPP_HARDENING_MODE_DEBUG
+
+# define _LIBCPP_ASSERTION_HANDLER(message) _LIBCPP_VERBOSE_ABORT("%s", message)
+
+#else
+
+# define _LIBCPP_ASSERTION_HANDLER(message) ((void)message, __builtin_trap())
+
+#endif // _LIBCPP_HARDENING_MODE == _LIBCPP_HARDENING_MODE_DEBUG
#endif // _LIBCPP___ASSERTION_HANDLER
>From 522100d40be08e67894416fb485e8be467160884 Mon Sep 17 00:00:00 2001
From: Konstantin Varlamov <varconsteq at gmail.com>
Date: Thu, 18 Jan 2024 02:40:42 -0800
Subject: [PATCH 02/11] Format
---
libcxx/test/support/check_assertion.h | 34 +++++++++----------
.../test_check_assertion.pass.cpp | 1 -
2 files changed, 16 insertions(+), 19 deletions(-)
diff --git a/libcxx/test/support/check_assertion.h b/libcxx/test/support/check_assertion.h
index 8e1493b70a66a6..229cd250e66f1b 100644
--- a/libcxx/test/support/check_assertion.h
+++ b/libcxx/test/support/check_assertion.h
@@ -207,33 +207,31 @@ std::string ToString(Outcome outcome) {
}
class DeathTestResult {
- public:
- DeathTestResult() = default;
- DeathTestResult(Outcome set_outcome, DeathCause set_cause, const std::string& set_failure_description = "")
- : outcome_(set_outcome), cause_(set_cause), failure_description_(set_failure_description) {}
-
- bool success() const { return outcome() == Outcome::Success; }
- Outcome outcome() const { return outcome_; }
- DeathCause cause() const { return cause_; }
- const std::string& failure_description() const { return failure_description_; }
-
- private:
- Outcome outcome_ = Outcome::Success;
- DeathCause cause_ = DeathCause::Unknown;
- std::string failure_description_;
+public:
+ DeathTestResult() = default;
+ DeathTestResult(Outcome set_outcome, DeathCause set_cause, const std::string& set_failure_description = "")
+ : outcome_(set_outcome), cause_(set_cause), failure_description_(set_failure_description) {}
+
+ bool success() const { return outcome() == Outcome::Success; }
+ Outcome outcome() const { return outcome_; }
+ DeathCause cause() const { return cause_; }
+ const std::string& failure_description() const { return failure_description_; }
+
+private:
+ Outcome outcome_ = Outcome::Success;
+ DeathCause cause_ = DeathCause::Unknown;
+ std::string failure_description_;
};
class DeathTest {
- public:
+public:
DeathTest() = default;
DeathTest(DeathTest const&) = delete;
DeathTest& operator=(DeathTest const&) = delete;
template <class Func>
DeathTestResult Run(DeathCause expected_cause, Func&& func, const AssertionInfoMatcher& matcher) {
- std::set_terminate([] {
- StopChildProcess(DeathCause::StdTerminate);
- });
+ std::set_terminate([] { StopChildProcess(DeathCause::StdTerminate); });
DeathCause cause = Run(func);
diff --git a/libcxx/test/support/test.support/test_check_assertion.pass.cpp b/libcxx/test/support/test.support/test_check_assertion.pass.cpp
index b45c101f567cda..a078f66cf0a19b 100644
--- a/libcxx/test/support/test.support/test_check_assertion.pass.cpp
+++ b/libcxx/test/support/test.support/test_check_assertion.pass.cpp
@@ -98,7 +98,6 @@ int main(int, char**) {
#endif
}
-
{ // Invalid cause -- child did not die.
TEST_DEATH_TEST(Outcome::InvalidCause, DeathCause::DidNotDie, ((void)0));
}
>From 895e6ad17876a34d069e5e5cc358fc4da42f4be2 Mon Sep 17 00:00:00 2001
From: Konstantin Varlamov <varconsteq at gmail.com>
Date: Thu, 18 Jan 2024 23:25:50 -0800
Subject: [PATCH 03/11] Fix GCC error
---
libcxx/test/support/check_assertion.h | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/libcxx/test/support/check_assertion.h b/libcxx/test/support/check_assertion.h
index 229cd250e66f1b..2a382c172564f5 100644
--- a/libcxx/test/support/check_assertion.h
+++ b/libcxx/test/support/check_assertion.h
@@ -175,6 +175,8 @@ std::string ToString(DeathCause cause) {
case DeathCause::Unknown:
return "<invalid cause (unknown)>";
}
+
+ assert(false && "Unreachable");
}
TEST_NORETURN void StopChildProcess(DeathCause cause) { std::exit(static_cast<int>(cause)); }
@@ -204,6 +206,8 @@ std::string ToString(Outcome outcome) {
case Outcome::InvalidCause:
return "invalid death cause";
}
+
+ assert(false && "Unreachable");
}
class DeathTestResult {
>From 119f7cdda0d98329ea1d2372d51204a5225b7515 Mon Sep 17 00:00:00 2001
From: Konstantin Varlamov <varconsteq at gmail.com>
Date: Fri, 19 Jan 2024 00:20:08 -0800
Subject: [PATCH 04/11] Feedback + other refactoring
---
libcxx/test/support/check_assertion.h | 239 ++++++------------
.../test_check_assertion.pass.cpp | 35 ++-
2 files changed, 92 insertions(+), 182 deletions(-)
diff --git a/libcxx/test/support/check_assertion.h b/libcxx/test/support/check_assertion.h
index 2a382c172564f5..deeba7e8f38ba2 100644
--- a/libcxx/test/support/check_assertion.h
+++ b/libcxx/test/support/check_assertion.h
@@ -15,6 +15,7 @@
#include <cstdio>
#include <cstdlib>
#include <exception>
+#include <functional>
#include <regex>
#include <sstream>
#include <string>
@@ -31,112 +32,51 @@
# error "C++11 or greater is required to use this header"
#endif
-struct AssertionInfoMatcher {
- // When printing the assertion message to `stderr`, delimit it with a marker to make it easier to match the message
- // later.
- static constexpr const char* Marker = "###";
-
- static const int any_line = -1;
- static constexpr const char* any_file = "*";
- static constexpr const char* any_msg = "*";
-
- constexpr AssertionInfoMatcher()
- : msg_(any_msg, __builtin_strlen(any_msg)), file_(any_file, __builtin_strlen(any_file)), line_(any_line) {}
- constexpr AssertionInfoMatcher(const char* msg, const char* file = any_file, int line = any_line)
- : is_empty_(false), msg_(msg, __builtin_strlen(msg)), file_(file, __builtin_strlen(file)), line_(line) {}
-
- bool CheckMatchInOutput(const std::string& output, std::string& error) const {
- // Extract information from the error message. This has to stay synchronized with how we format assertions in the
- // library.
- std::regex message_format(".*###\\n(.*):(\\d+): assertion (.*) failed: (.*)\\n###");
-
- std::smatch match_result;
- bool has_match = std::regex_match(output, match_result, message_format);
- assert(has_match);
- assert(match_result.size() == 5);
-
- const std::string& file = match_result[1];
- int line = std::stoi(match_result[2]);
- // Omitting `expression` in `match_result[3]`
- const std::string& failure_reason = match_result[4];
-
- bool result = Matches(file, line, failure_reason);
- if (!result) {
- error = FormatMatchingError(file, line, failure_reason);
- }
- return result;
- }
-
- bool Matches(const std::string& file, int line, const std::string& message) const {
- assert(!empty() && "Empty matcher");
- return CheckLineMatches(line) && CheckFileMatches(file) && CheckMessageMatches(message);
- }
-
- std::string FormatMatchingError(const std::string& file, int line, const std::string& message) const {
- std::stringstream output;
- output //
- << "Expected message: '" << msg_.data() << "'\n" //
- << "Actual message: '" << message.c_str() << "'\n" //
- << "Expected location: " << FormatLocation(file_, line_) << "\n" //
- << "Actual location: " << FormatLocation(file, line) << "\n";
- return output.str();
- }
-
- static std::string FormatLocation(std::string_view file, int line) {
- std::string result;
- result += (file == any_file ? "*" : std::string(file)) + ":";
- result += (line == any_line ? "*" : std::to_string(line));
- return result;
- }
-
- bool empty() const { return is_empty_; }
- bool IsAnyMatcher() const { return msg_ == any_msg && file_ == any_file && line_ == any_line; }
-
-private:
- bool CheckLineMatches(int got_line) const {
- if (line_ == any_line)
- return true;
- return got_line == line_;
- }
-
- bool CheckFileMatches(std::string_view got_file) const {
- assert(!empty() && "empty matcher");
- if (file_ == any_file)
- return true;
- std::size_t found_at = got_file.find(file_);
- if (found_at == std::string_view::npos)
- return false;
- // require the match start at the beginning of the file or immediately after
- // a directory separator.
- if (found_at != 0) {
- char last_char = got_file[found_at - 1];
- if (last_char != '/' && last_char != '\\')
- return false;
- }
- // require the match goes until the end of the string.
- return got_file.substr(found_at) == file_;
+// When printing the assertion message to `stderr`, delimit it with a marker to make it easier to match the message
+// later.
+static constexpr const char* Marker = "###";
+
+// (success, error-message-if-failed)
+using MatchResult = std::pair<bool, std::string>;
+using Matcher = std::function<MatchResult(const std::string& /*text*/)>;
+
+MatchResult MatchAssertionMessage(const std::string& text, std::string_view expected_message) {
+ // Extract information from the error message. This has to stay synchronized with how we format assertions in the
+ // library.
+ std::regex assertion_format(".*###\\n(.*):(\\d+): assertion (.*) failed: (.*)\\n###");
+
+ std::smatch match_result;
+ bool has_match = std::regex_match(text, match_result, assertion_format);
+ assert(has_match);
+ assert(match_result.size() == 5);
+
+ const std::string& file = match_result[1];
+ int line = std::stoi(match_result[2]);
+ // Omitting `expression` in `match_result[3]`
+ const std::string& assertion_message = match_result[4];
+
+ bool result = assertion_message.find(expected_message) != std::string::npos;
+ if (!result) {
+ std::stringstream matching_error;
+ matching_error //
+ << "Expected message: '" << expected_message.data() << "'\n" //
+ << "Actual message: '" << assertion_message.c_str() << "'\n" //
+ << "Source location: " << file << ":" << std::to_string(line) << "\n";
+ return MatchResult(/*success=*/false, matching_error.str());
}
- bool CheckMessageMatches(std::string_view got_msg) const {
- assert(!empty() && "empty matcher");
- if (msg_ == any_msg)
- return true;
- std::size_t found_at = got_msg.find(msg_);
- if (found_at == std::string_view::npos)
- return false;
- // Allow any match
- return true;
- }
+ return MatchResult(/*success=*/true, /*maybe_error=*/"");
+}
-private:
- bool is_empty_ = true;
- ;
- std::string_view msg_;
- std::string_view file_;
- int line_;
-};
+Matcher MakeAssertionMessageMatcher(std::string_view assertion_message) {
+ return [=] (const std::string& text) {
+ return MatchAssertionMessage(text, assertion_message);
+ };
+}
-static constexpr AssertionInfoMatcher AnyMatcher(AssertionInfoMatcher::any_msg);
+Matcher MakeAnyMatcher() {
+ return [](const std::string&) { return MatchResult(/*success=*/true, /*maybe_error=*/""); };
+}
enum class DeathCause {
// Valid causes
@@ -169,11 +109,11 @@ std::string ToString(DeathCause cause) {
case DeathCause::Trap:
return "trap";
case DeathCause::DidNotDie:
- return "<invalid cause (did not die)>";
+ return "<invalid cause (child did not die)>";
case DeathCause::SetupFailure:
- return "<invalid cause (setup failure)>";
+ return "<invalid cause (child failed to set up test environment)>";
case DeathCause::Unknown:
- return "<invalid cause (unknown)>";
+ return "<invalid cause (cause unknown)>";
}
assert(false && "Unreachable");
@@ -191,7 +131,7 @@ DeathCause ConvertToDeathCause(int val) {
enum class Outcome {
Success,
UnexpectedCause,
- UnexpectedAbortMessage,
+ UnexpectedErrorMessage,
InvalidCause,
};
@@ -201,8 +141,8 @@ std::string ToString(Outcome outcome) {
return "success";
case Outcome::UnexpectedCause:
return "unexpected death cause";
- case Outcome::UnexpectedAbortMessage:
- return "unexpected verbose abort message";
+ case Outcome::UnexpectedErrorMessage:
+ return "unexpected error message";
case Outcome::InvalidCause:
return "invalid death cause";
}
@@ -234,53 +174,31 @@ class DeathTest {
DeathTest& operator=(DeathTest const&) = delete;
template <class Func>
- DeathTestResult Run(DeathCause expected_cause, Func&& func, const AssertionInfoMatcher& matcher) {
+ DeathTestResult Run(DeathCause expected_cause, Func&& func, const Matcher& matcher) {
std::set_terminate([] { StopChildProcess(DeathCause::StdTerminate); });
DeathCause cause = Run(func);
- auto DescribeDeathCauseMismatch = [](DeathCause expected, DeathCause actual) {
- std::stringstream output;
- output //
- << "Child died, but with a different death cause\n" //
- << "Expected cause: " << ToString(expected) << "\n" //
- << "Actual cause: " << ToString(actual) << "\n";
- return output.str();
- };
-
- switch (cause) {
- case DeathCause::StdTerminate:
- case DeathCause::Trap:
- if (expected_cause != cause) {
- auto failure_description = DescribeDeathCauseMismatch(expected_cause, cause);
- return DeathTestResult(Outcome::UnexpectedCause, cause, failure_description);
- }
- return DeathTestResult(Outcome::Success, cause);
-
- case DeathCause::VerboseAbort: {
- if (expected_cause != cause) {
- auto failure_description = DescribeDeathCauseMismatch(expected_cause, cause);
- return DeathTestResult(Outcome::UnexpectedCause, cause, failure_description);
- }
+ if (!IsValidCause(cause)) {
+ return DeathTestResult(Outcome::InvalidCause, cause, ToString(cause));
+ }
- std::string maybe_error;
- if (matcher.CheckMatchInOutput(getChildStdErr(), maybe_error)) {
- return DeathTestResult(Outcome::Success, cause);
- }
- auto failure_description = std::string("Child died, but with a different verbose abort message\n") + maybe_error;
- return DeathTestResult(Outcome::UnexpectedAbortMessage, cause, failure_description);
+ if (expected_cause != cause) {
+ std::stringstream failure_description;
+ failure_description //
+ << "Child died, but with a different death cause\n" //
+ << "Expected cause: " << ToString(expected_cause) << "\n" //
+ << "Actual cause: " << ToString(cause) << "\n";
+ return DeathTestResult(Outcome::UnexpectedCause, cause, failure_description.str());
}
- // Invalid causes.
- case DeathCause::DidNotDie:
- return DeathTestResult(Outcome::InvalidCause, cause, "Child did not die");
- case DeathCause::SetupFailure:
- return DeathTestResult(Outcome::InvalidCause, cause, "Child failed to set up test environment");
- case DeathCause::Unknown:
- return DeathTestResult(Outcome::InvalidCause, cause, "Cause unknown");
+ MatchResult match_result = matcher(GetChildStdErr());
+ if (!match_result.first) {
+ auto failure_description = std::string("Child died, but with a different error message\n") + match_result.second;
+ return DeathTestResult(Outcome::UnexpectedErrorMessage, cause, failure_description);
}
- assert(false && "Unreachable");
+ return DeathTestResult(Outcome::Success, cause);
}
void PrintFailureDetails(std::string_view failure_description, std::string_view stmt, DeathCause cause) const {
@@ -288,19 +206,19 @@ class DeathTest {
stderr, "Failure: EXPECT_DEATH( %s ) failed!\n(reason: %s)\n\n", stmt.data(), failure_description.data());
if (cause != DeathCause::Unknown) {
- std::fprintf(stderr, "child exit code: %d\n", getChildExitCode());
+ std::fprintf(stderr, "child exit code: %d\n", GetChildExitCode());
}
- std::fprintf(stderr, "---------- standard err ----------\n%s", getChildStdErr().c_str());
+ std::fprintf(stderr, "---------- standard err ----------\n%s", GetChildStdErr().c_str());
std::fprintf(stderr, "\n----------------------------------\n");
- std::fprintf(stderr, "---------- standard out ----------\n%s", getChildStdOut().c_str());
+ std::fprintf(stderr, "---------- standard out ----------\n%s", GetChildStdOut().c_str());
std::fprintf(stderr, "\n----------------------------------\n");
};
- int getChildExitCode() const { return exit_code_; }
- std::string const& getChildStdOut() const { return stdout_from_child_; }
- std::string const& getChildStdErr() const { return stderr_from_child_; }
-
private:
+ int GetChildExitCode() const { return exit_code_; }
+ std::string const& GetChildStdOut() const { return stdout_from_child_; }
+ std::string const& GetChildStdErr() const { return stderr_from_child_; }
+
template <class Func>
DeathCause Run(Func&& f) {
int pipe_res = pipe(stdout_pipe_fd_);
@@ -378,11 +296,8 @@ class DeathTest {
}
int GetStdOutReadFD() const { return stdout_pipe_fd_[0]; }
-
int GetStdOutWriteFD() const { return stdout_pipe_fd_[1]; }
-
int GetStdErrReadFD() const { return stderr_pipe_fd_[0]; }
-
int GetStdErrWriteFD() const { return stderr_pipe_fd_[1]; }
pid_t child_pid_ = -1;
@@ -398,9 +313,9 @@ void std::__libcpp_verbose_abort(char const* format, ...) {
va_list args;
va_start(args, format);
- std::fprintf(stderr, "%s\n", AssertionInfoMatcher::Marker);
+ std::fprintf(stderr, "%s\n", Marker);
std::vfprintf(stderr, format, args);
- std::fprintf(stderr, "%s", AssertionInfoMatcher::Marker);
+ std::fprintf(stderr, "%s", Marker);
va_end(args);
@@ -409,7 +324,7 @@ void std::__libcpp_verbose_abort(char const* format, ...) {
#endif // _LIBCPP_VERSION
template <class Func>
-inline bool ExpectDeath(DeathCause expected_cause, const char* stmt, Func&& func, AssertionInfoMatcher matcher) {
+bool ExpectDeath(DeathCause expected_cause, const char* stmt, Func&& func, const Matcher& matcher) {
assert(IsValidCause(expected_cause));
DeathTest test_case;
@@ -422,8 +337,8 @@ inline bool ExpectDeath(DeathCause expected_cause, const char* stmt, Func&& func
}
template <class Func>
-inline bool ExpectDeath(DeathCause expected_cause, const char* stmt, Func&& func) {
- return ExpectDeath(expected_cause, stmt, func, AnyMatcher);
+bool ExpectDeath(DeathCause expected_cause, const char* stmt, Func&& func) {
+ return ExpectDeath(expected_cause, stmt, func, MakeAnyMatcher());
}
// clang-format off
@@ -438,7 +353,7 @@ inline bool ExpectDeath(DeathCause expected_cause, const char* stmt, Func&& func
#if _LIBCPP_HARDENING_MODE == _LIBCPP_HARDENING_MODE_DEBUG
#define TEST_LIBCPP_ASSERT_FAILURE(expr, message) \
- assert(( ExpectDeath(DeathCause::VerboseAbort, #expr, [&]() { (void)(expr); }, AssertionInfoMatcher(message)) ))
+ assert(( ExpectDeath(DeathCause::VerboseAbort, #expr, [&]() { (void)(expr); }, MakeAssertionMessageMatcher(message)) ))
#else
#define TEST_LIBCPP_ASSERT_FAILURE(expr, message) \
assert(( ExpectDeath(DeathCause::Trap, #expr, [&]() { (void)(expr); }) ))
diff --git a/libcxx/test/support/test.support/test_check_assertion.pass.cpp b/libcxx/test/support/test.support/test_check_assertion.pass.cpp
index a078f66cf0a19b..09f1429f71fdae 100644
--- a/libcxx/test/support/test.support/test_check_assertion.pass.cpp
+++ b/libcxx/test/support/test.support/test_check_assertion.pass.cpp
@@ -18,8 +18,8 @@
#include "check_assertion.h"
template <class Func>
-inline bool TestDeathTest(
- Outcome expected_outcome, DeathCause expected_cause, const char* stmt, Func&& func, AssertionInfoMatcher matcher) {
+bool TestDeathTest(
+ Outcome expected_outcome, DeathCause expected_cause, const char* stmt, Func&& func, const Matcher& matcher) {
DeathTest test_case;
DeathTestResult test_result = test_case.Run(expected_cause, func, matcher);
std::string maybe_failure_description;
@@ -54,30 +54,29 @@ inline bool TestDeathTest(
// clang-format off
#define TEST_DEATH_TEST(outcome, cause, ...) \
- assert(( TestDeathTest(outcome, cause, #__VA_ARGS__, [&]() { __VA_ARGS__; }, AnyMatcher) ))
+ assert(( TestDeathTest(outcome, cause, #__VA_ARGS__, [&]() { __VA_ARGS__; }, MakeAnyMatcher()) ))
#define TEST_DEATH_TEST_MATCHES(outcome, cause, matcher, ...) \
assert(( TestDeathTest(outcome, cause, #__VA_ARGS__, [&]() { __VA_ARGS__; }, matcher) ))
// clang-format on
-int main(int, char**) {
- { // Success -- verbose abort with any matcher.
- auto fail_assert = [] { _LIBCPP_ASSERT(false, "Some message"); };
#if _LIBCPP_HARDENING_MODE == _LIBCPP_HARDENING_MODE_DEBUG
- TEST_DEATH_TEST_MATCHES(Outcome::Success, DeathCause::VerboseAbort, AnyMatcher, fail_assert());
+DeathCause assertion_death_cause = DeathCause::VerboseAbort;
#else
- TEST_DEATH_TEST_MATCHES(Outcome::Success, DeathCause::Trap, AnyMatcher, fail_assert());
+DeathCause assertion_death_cause = DeathCause::Trap;
#endif
+
+int main(int, char**) {
+
+ { // Success -- verbose abort with any matcher.
+ auto fail_assert = [] { _LIBCPP_ASSERT(false, "Some message"); };
+ TEST_DEATH_TEST_MATCHES(Outcome::Success, assertion_death_cause, MakeAnyMatcher(), fail_assert());
}
{ // Success -- verbose abort with a specific matcher.
auto fail_assert = [] { _LIBCPP_ASSERT(false, "Some message"); };
- AssertionInfoMatcher matcher("Some message");
-#if _LIBCPP_HARDENING_MODE == _LIBCPP_HARDENING_MODE_DEBUG
- TEST_DEATH_TEST_MATCHES(Outcome::Success, DeathCause::VerboseAbort, matcher, fail_assert());
-#else
- TEST_DEATH_TEST_MATCHES(Outcome::Success, DeathCause::Trap, matcher, fail_assert());
-#endif
+ Matcher matcher = MakeAssertionMessageMatcher("Some message");
+ TEST_DEATH_TEST_MATCHES(Outcome::Success, assertion_death_cause, matcher, fail_assert());
}
{ // Success -- `std::terminate`.
@@ -90,12 +89,8 @@ int main(int, char**) {
{ // Error message doesn't match.
auto fail_assert = [] { _LIBCPP_ASSERT(false, "Actual message doesn't match"); };
- AssertionInfoMatcher matcher("Bad expected message");
-#if _LIBCPP_HARDENING_MODE == _LIBCPP_HARDENING_MODE_DEBUG
- TEST_DEATH_TEST_MATCHES(Outcome::UnexpectedAbortMessage, DeathCause::VerboseAbort, matcher, fail_assert());
-#else
- TEST_DEATH_TEST_MATCHES(Outcome::Success, DeathCause::Trap, matcher, fail_assert());
-#endif
+ Matcher matcher = MakeAssertionMessageMatcher("Bad expected message");
+ TEST_DEATH_TEST_MATCHES(Outcome::UnexpectedErrorMessage, assertion_death_cause, matcher, fail_assert());
}
{ // Invalid cause -- child did not die.
>From 43c33cf8ed31758979d9f94393fe05bbc52097e9 Mon Sep 17 00:00:00 2001
From: Konstantin Varlamov <varconsteq at gmail.com>
Date: Fri, 19 Jan 2024 00:29:19 -0800
Subject: [PATCH 05/11] Minor refactoring, clang-format
---
libcxx/test/support/check_assertion.h | 14 ++++++++------
1 file changed, 8 insertions(+), 6 deletions(-)
diff --git a/libcxx/test/support/check_assertion.h b/libcxx/test/support/check_assertion.h
index deeba7e8f38ba2..1fa5cc72adbc24 100644
--- a/libcxx/test/support/check_assertion.h
+++ b/libcxx/test/support/check_assertion.h
@@ -38,7 +38,7 @@ static constexpr const char* Marker = "###";
// (success, error-message-if-failed)
using MatchResult = std::pair<bool, std::string>;
-using Matcher = std::function<MatchResult(const std::string& /*text*/)>;
+using Matcher = std::function<MatchResult(const std::string& /*text*/)>;
MatchResult MatchAssertionMessage(const std::string& text, std::string_view expected_message) {
// Extract information from the error message. This has to stay synchronized with how we format assertions in the
@@ -55,7 +55,7 @@ MatchResult MatchAssertionMessage(const std::string& text, std::string_view expe
// Omitting `expression` in `match_result[3]`
const std::string& assertion_message = match_result[4];
- bool result = assertion_message.find(expected_message) != std::string::npos;
+ bool result = assertion_message == expected_message;
if (!result) {
std::stringstream matching_error;
matching_error //
@@ -69,13 +69,15 @@ MatchResult MatchAssertionMessage(const std::string& text, std::string_view expe
}
Matcher MakeAssertionMessageMatcher(std::string_view assertion_message) {
- return [=] (const std::string& text) {
+ return [=](const std::string& text) { //
return MatchAssertionMessage(text, assertion_message);
};
}
Matcher MakeAnyMatcher() {
- return [](const std::string&) { return MatchResult(/*success=*/true, /*maybe_error=*/""); };
+ return [](const std::string&) { //
+ return MatchResult(/*success=*/true, /*maybe_error=*/"");
+ };
}
enum class DeathCause {
@@ -185,8 +187,8 @@ class DeathTest {
if (expected_cause != cause) {
std::stringstream failure_description;
- failure_description //
- << "Child died, but with a different death cause\n" //
+ failure_description //
+ << "Child died, but with a different death cause\n" //
<< "Expected cause: " << ToString(expected_cause) << "\n" //
<< "Actual cause: " << ToString(cause) << "\n";
return DeathTestResult(Outcome::UnexpectedCause, cause, failure_description.str());
>From a95509b73dd8a6f84f8210df56131c8d37ddc6f2 Mon Sep 17 00:00:00 2001
From: Konstantin Varlamov <varconsteq at gmail.com>
Date: Fri, 19 Jan 2024 02:53:31 -0800
Subject: [PATCH 06/11] Refactoring, more feedback
---
...tomize_verbose_abort.compile-time.pass.cpp | 3 +-
...customize_verbose_abort.link-time.pass.cpp | 3 +-
.../assertions/default_verbose_abort.pass.cpp | 4 +-
.../test_check_assertion.pass.cpp | 71 ++++++++++++-------
4 files changed, 51 insertions(+), 30 deletions(-)
diff --git a/libcxx/test/libcxx/assertions/customize_verbose_abort.compile-time.pass.cpp b/libcxx/test/libcxx/assertions/customize_verbose_abort.compile-time.pass.cpp
index d176d8a12875e6..69154c3f7eaffa 100644
--- a/libcxx/test/libcxx/assertions/customize_verbose_abort.compile-time.pass.cpp
+++ b/libcxx/test/libcxx/assertions/customize_verbose_abort.compile-time.pass.cpp
@@ -8,7 +8,6 @@
// This compile-time customization requires cross-file macros, which doesn't work with modules.
// UNSUPPORTED: clang-modules-build
-// REQUIRES: libcpp-hardening-mode=debug
// Make sure that we can customize the verbose termination function at compile-time by
// defining _LIBCPP_VERBOSE_ABORT ourselves. Note that this does not have any
@@ -23,6 +22,6 @@ void my_abort(char const*, ...) {
}
int main(int, char**) {
- _LIBCPP_ASSERT(false, "message");
+ _LIBCPP_VERBOSE_ABORT("%s", "message");
return EXIT_FAILURE;
}
diff --git a/libcxx/test/libcxx/assertions/customize_verbose_abort.link-time.pass.cpp b/libcxx/test/libcxx/assertions/customize_verbose_abort.link-time.pass.cpp
index c82aaea6ba30df..585ab73f2cb261 100644
--- a/libcxx/test/libcxx/assertions/customize_verbose_abort.link-time.pass.cpp
+++ b/libcxx/test/libcxx/assertions/customize_verbose_abort.link-time.pass.cpp
@@ -11,7 +11,6 @@
// We flag uses of the verbose termination function in older dylibs at compile-time to avoid runtime
// failures when back-deploying.
// XFAIL: availability-verbose_abort-missing
-// REQUIRES: libcpp-hardening-mode=debug
#include <cstdlib>
@@ -20,6 +19,6 @@ void std::__libcpp_verbose_abort(char const*, ...) {
}
int main(int, char**) {
- _LIBCPP_ASSERT(false, "message");
+ std::__libcpp_verbose_abort("%s", "message");
return EXIT_FAILURE;
}
diff --git a/libcxx/test/libcxx/assertions/default_verbose_abort.pass.cpp b/libcxx/test/libcxx/assertions/default_verbose_abort.pass.cpp
index 29ef10016c1a37..18cc7a9521e498 100644
--- a/libcxx/test/libcxx/assertions/default_verbose_abort.pass.cpp
+++ b/libcxx/test/libcxx/assertions/default_verbose_abort.pass.cpp
@@ -7,8 +7,8 @@
//===----------------------------------------------------------------------===//
// Test that the default verbose termination function aborts the program.
-// REQUIRES: libcpp-hardening-mode=debug
+#include <__verbose_abort>
#include <csignal>
#include <cstdlib>
@@ -20,6 +20,6 @@ void signal_handler(int signal) {
int main(int, char**) {
if (std::signal(SIGABRT, signal_handler) != SIG_ERR)
- _LIBCPP_ASSERT(false, "foo");
+ std::__libcpp_verbose_abort("%s", "foo");
return EXIT_FAILURE;
}
diff --git a/libcxx/test/support/test.support/test_check_assertion.pass.cpp b/libcxx/test/support/test.support/test_check_assertion.pass.cpp
index 09f1429f71fdae..137506ceedbc2b 100644
--- a/libcxx/test/support/test.support/test_check_assertion.pass.cpp
+++ b/libcxx/test/support/test.support/test_check_assertion.pass.cpp
@@ -20,8 +20,17 @@
template <class Func>
bool TestDeathTest(
Outcome expected_outcome, DeathCause expected_cause, const char* stmt, Func&& func, const Matcher& matcher) {
+ auto get_matcher = [&] {
+#if _LIBCPP_HARDENING_MODE == _LIBCPP_HARDENING_MODE_DEBUG
+ return matcher;
+#else
+ (void)matcher;
+ return MakeAnyMatcher();
+#endif
+ };
+
DeathTest test_case;
- DeathTestResult test_result = test_case.Run(expected_cause, func, matcher);
+ DeathTestResult test_result = test_case.Run(expected_cause, func, get_matcher());
std::string maybe_failure_description;
Outcome outcome = test_result.outcome();
@@ -67,38 +76,52 @@ DeathCause assertion_death_cause = DeathCause::Trap;
#endif
int main(int, char**) {
+ auto fail_assert = [] { _LIBCPP_ASSERT(false, "Some message"); };
+ Matcher good_matcher = MakeAssertionMessageMatcher("Some message");
+ Matcher bad_matcher = MakeAssertionMessageMatcher("Bad expected message");
+
+ // Test the implementation of death tests. We're bypassing the assertions added by the actual `EXPECT_DEATH` macros
+ // which allows us to test failure cases (where the assertion would fail) as well.
+ {
+ // Success -- `std::terminate`.
+ TEST_DEATH_TEST(Outcome::Success, DeathCause::StdTerminate, std::terminate());
- { // Success -- verbose abort with any matcher.
- auto fail_assert = [] { _LIBCPP_ASSERT(false, "Some message"); };
+ (void)fail_assert;
+ // Success -- trapping.
+ TEST_DEATH_TEST(Outcome::Success, DeathCause::Trap, __builtin_trap());
+
+ // Success -- assertion failure with any matcher.
TEST_DEATH_TEST_MATCHES(Outcome::Success, assertion_death_cause, MakeAnyMatcher(), fail_assert());
- }
- { // Success -- verbose abort with a specific matcher.
- auto fail_assert = [] { _LIBCPP_ASSERT(false, "Some message"); };
- Matcher matcher = MakeAssertionMessageMatcher("Some message");
- TEST_DEATH_TEST_MATCHES(Outcome::Success, assertion_death_cause, matcher, fail_assert());
- }
+ // Success -- assertion failure with a specific matcher.
+ TEST_DEATH_TEST_MATCHES(Outcome::Success, assertion_death_cause, good_matcher, fail_assert());
- { // Success -- `std::terminate`.
- TEST_DEATH_TEST(Outcome::Success, DeathCause::StdTerminate, std::terminate());
- }
+#if _LIBCPP_HARDENING_MODE == _LIBCPP_HARDENING_MODE_DEBUG
+ // Failure -- error message doesn't match.
+ TEST_DEATH_TEST_MATCHES(Outcome::UnexpectedErrorMessage, assertion_death_cause, bad_matcher, fail_assert());
+#endif
- { // Success -- trapping.
- TEST_DEATH_TEST(Outcome::Success, DeathCause::Trap, __builtin_trap());
- }
+ // Invalid cause -- child did not die.
+ TEST_DEATH_TEST(Outcome::InvalidCause, DeathCause::DidNotDie, ((void)0));
- { // Error message doesn't match.
- auto fail_assert = [] { _LIBCPP_ASSERT(false, "Actual message doesn't match"); };
- Matcher matcher = MakeAssertionMessageMatcher("Bad expected message");
- TEST_DEATH_TEST_MATCHES(Outcome::UnexpectedErrorMessage, assertion_death_cause, matcher, fail_assert());
+ // Invalid cause -- unknown.
+ TEST_DEATH_TEST(Outcome::InvalidCause, DeathCause::Unknown, std::exit(13));
}
- { // Invalid cause -- child did not die.
- TEST_DEATH_TEST(Outcome::InvalidCause, DeathCause::DidNotDie, ((void)0));
- }
+ // Test the `EXPECT_DEATH` macros themselves. Since they assert success, we can only test successful cases.
+ {
+ auto invoke_abort = [] { _LIBCPP_VERBOSE_ABORT("contains some message"); };
- { // Invalid cause -- unknown.
- TEST_DEATH_TEST(Outcome::InvalidCause, DeathCause::Unknown, std::exit(13));
+ auto simple_matcher = [] (const std::string& text) {
+ bool success = text.find("some") != std::string::npos;
+ return MatchResult(success, "");
+ };
+
+ EXPECT_DEATH(invoke_abort());
+ EXPECT_DEATH_MATCHES(MakeAnyMatcher(), invoke_abort());
+ EXPECT_DEATH_MATCHES(simple_matcher, invoke_abort());
+ EXPECT_STD_TERMINATE([] { std::terminate(); });
+ TEST_LIBCPP_ASSERT_FAILURE(fail_assert(), "Some message");
}
return 0;
>From 5727f38fb949c39a89c811ac9dc066539af3f86a Mon Sep 17 00:00:00 2001
From: Konstantin Varlamov <varconsteq at gmail.com>
Date: Fri, 19 Jan 2024 03:06:08 -0800
Subject: [PATCH 07/11] Add a comment
---
libcxx/test/support/check_assertion.h | 1 +
1 file changed, 1 insertion(+)
diff --git a/libcxx/test/support/check_assertion.h b/libcxx/test/support/check_assertion.h
index 1fa5cc72adbc24..485f8103c7ad8d 100644
--- a/libcxx/test/support/check_assertion.h
+++ b/libcxx/test/support/check_assertion.h
@@ -289,6 +289,7 @@ class DeathTest {
if (WIFSIGNALED(status_value)) {
exit_code_ = WTERMSIG(status_value);
+ // `__builtin_trap` generqtes `SIGILL` on x86 and `SIGTRAP` on ARM.
if (exit_code_ == SIGILL || exit_code_ == SIGTRAP) {
return DeathCause::Trap;
}
>From de5e151259849acf8ab75043701c9ede6b26f5bd Mon Sep 17 00:00:00 2001
From: Konstantin Varlamov <varconsteq at gmail.com>
Date: Fri, 19 Jan 2024 03:19:50 -0800
Subject: [PATCH 08/11] Update docs
---
libcxx/docs/BuildingLibcxx.rst | 20 ++++++++------------
libcxx/docs/ReleaseNotes/18.rst | 21 ++++++++++++++-------
2 files changed, 22 insertions(+), 19 deletions(-)
diff --git a/libcxx/docs/BuildingLibcxx.rst b/libcxx/docs/BuildingLibcxx.rst
index 11e250e3f3735a..9a250e7cd79059 100644
--- a/libcxx/docs/BuildingLibcxx.rst
+++ b/libcxx/docs/BuildingLibcxx.rst
@@ -485,18 +485,14 @@ LLVM-specific options
.. _assertion-handler:
Overriding the default assertion handler
-==========================================
-
-When the library wants to terminate due to an unforeseen condition (such as
-a hardening assertion failure), the program is aborted through a special verbose
-termination function. The library provides a default function that prints an
-error message and calls ``std::abort()``. Note that this function is provided by
-the static or shared library, so it is only available when deploying to
-a platform where the compiled library is sufficiently recent. On older
-platforms, the program will terminate in an unspecified unsuccessful manner, but
-the quality of diagnostics won't be great.
-
-However, vendors can also override that mechanism at CMake configuration time.
+========================================
+
+When the library wants to terminate due to a hardening assertion failure, the
+program is aborted by invoking a trap instruction (or in debug mode, by
+a special verbose termination function that prints an error message and calls
+``std::abort()``). However, vendors can also override that mechanism at CMake
+configuration time.
+
When a hardening assertion fails, the library invokes the
``_LIBCPP_ASSERTION_HANDLER`` macro. A vendor may provide a header that contains
a custom definition of this macro and specify the path to the header via the
diff --git a/libcxx/docs/ReleaseNotes/18.rst b/libcxx/docs/ReleaseNotes/18.rst
index 77b7939a0c0ac9..9cc024c3d7634e 100644
--- a/libcxx/docs/ReleaseNotes/18.rst
+++ b/libcxx/docs/ReleaseNotes/18.rst
@@ -111,13 +111,18 @@ Deprecations and Removals
macro is provided to restore the previous behavior, and it will be supported in the LLVM 18 release only.
In LLVM 19 and beyond, ``_LIBCPP_ENABLE_NARROWING_CONVERSIONS_IN_VARIANT`` will not be honored anymore.
-- The only supported way to customize the assertion handler that gets invoked when a hardening assertion fails
- is now by setting the ``LIBCXX_ASSERTION_HANDLER_FILE`` CMake variable and providing a custom header. See
- the documentation on overriding the default assertion handler for details.
+- Overriding `__libcpp_verbose_abort` no longer has any effect on library assertions. The only supported way
+ to customize the assertion handler that gets invoked when a hardening assertion fails is now by setting the
+ ``LIBCXX_ASSERTION_HANDLER_FILE`` CMake variable and providing a custom header. See the documentation on
+ overriding the default assertion handler for details. The ability to override `__libcpp_verbose_abort` will
+ be removed in an upcoming release in favor of the new overriding mechanism.
+
+- In safe mode (which is now equivalent to the ``extensive`` hardening mode), a failed assertion will now
+ generate a trap rather than a call to verbose abort.
- The ``_LIBCPP_AVAILABILITY_CUSTOM_VERBOSE_ABORT_PROVIDED`` macro is not honored anymore in LLVM 18.
- Please see the updated documentation about the hardening modes in libc++ and in particular the
- ``_LIBCPP_VERBOSE_ABORT`` macro for details.
+ Please see the updated documentation about the hardening modes in libc++ and in particular on
+ overriding the default assertion handler.
- The headers ``<experimental/deque>``, ``<experimental/forward_list>``, ``<experimental/list>``,
``<experimental/map>``, ``<experimental/memory_resource>``, ``<experimental/regex>``, ``<experimental/set>``,
@@ -140,13 +145,15 @@ Deprecations and Removals
Upcoming Deprecations and Removals
----------------------------------
+- ``__libcpp_verbose_abort`` and the ability to override this function will be removed in an upcoming release.
+
LLVM 19
~~~~~~~
- The ``LIBCXX_ENABLE_ASSERTIONS`` CMake variable that was used to enable the safe mode will be deprecated and setting
it will trigger an error; use the ``LIBCXX_HARDENING_MODE`` variable with the value ``extensive`` instead. Similarly,
- the ``_LIBCPP_ENABLE_ASSERTIONS`` macro will be deprecated (setting it to ``1`` still enables the extensive mode the
- LLVM 19 release while also issuing a deprecation warning). See :ref:`the hardening documentation
+ the ``_LIBCPP_ENABLE_ASSERTIONS`` macro will be deprecated (setting it to ``1`` still enables the extensive mode in
+ the LLVM 19 release while also issuing a deprecation warning). See :ref:`the hardening documentation
<using-hardening-modes>` for more details.
- The base template for ``std::char_traits`` has been marked as deprecated and will be removed in LLVM 19. If you
>From e2a162c9366576892ae9f535250c529613c7bcaf Mon Sep 17 00:00:00 2001
From: Konstantin Varlamov <varconsteq at gmail.com>
Date: Fri, 19 Jan 2024 03:20:39 -0800
Subject: [PATCH 09/11] format
---
libcxx/test/support/test.support/test_check_assertion.pass.cpp | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/libcxx/test/support/test.support/test_check_assertion.pass.cpp b/libcxx/test/support/test.support/test_check_assertion.pass.cpp
index 137506ceedbc2b..ce0c30ad4069a3 100644
--- a/libcxx/test/support/test.support/test_check_assertion.pass.cpp
+++ b/libcxx/test/support/test.support/test_check_assertion.pass.cpp
@@ -112,7 +112,7 @@ int main(int, char**) {
{
auto invoke_abort = [] { _LIBCPP_VERBOSE_ABORT("contains some message"); };
- auto simple_matcher = [] (const std::string& text) {
+ auto simple_matcher = [](const std::string& text) {
bool success = text.find("some") != std::string::npos;
return MatchResult(success, "");
};
>From f3b6fd96fb476f35af891181e87d3a77a6c4caa5 Mon Sep 17 00:00:00 2001
From: Konstantin Varlamov <varconsteq at gmail.com>
Date: Fri, 19 Jan 2024 11:39:44 -0800
Subject: [PATCH 10/11] Feedback
---
libcxx/docs/BuildingLibcxx.rst | 27 ++++++++++---------
libcxx/docs/ReleaseNotes/18.rst | 2 +-
.../test_check_assertion.pass.cpp | 1 -
.../vendor/llvm/default_assertion_handler.in | 1 +
4 files changed, 16 insertions(+), 15 deletions(-)
diff --git a/libcxx/docs/BuildingLibcxx.rst b/libcxx/docs/BuildingLibcxx.rst
index 9a250e7cd79059..dcd05a28f36d18 100644
--- a/libcxx/docs/BuildingLibcxx.rst
+++ b/libcxx/docs/BuildingLibcxx.rst
@@ -490,19 +490,20 @@ Overriding the default assertion handler
When the library wants to terminate due to a hardening assertion failure, the
program is aborted by invoking a trap instruction (or in debug mode, by
a special verbose termination function that prints an error message and calls
-``std::abort()``). However, vendors can also override that mechanism at CMake
-configuration time.
-
-When a hardening assertion fails, the library invokes the
-``_LIBCPP_ASSERTION_HANDLER`` macro. A vendor may provide a header that contains
-a custom definition of this macro and specify the path to the header via the
-``LIBCXX_ASSERTION_HANDLER_FILE`` CMake variable. If provided, this header will
-be included by the library and replace the default implementation. The header
-must not include any standard library headers (directly or transitively) because
-doing so will almost always create a circular dependency. The
-``_LIBCPP_ASSERTION_HANDLER(message)`` macro takes a single parameter that
-contains an error message explaining the hardening failure and some details
-about the source location that triggered it.
+``std::abort()``). This is done to minimize the code size impact of enabling
+hardening in the library. However, vendors can also override that mechanism at
+CMake configuration time.
+
+Under the hood, a hardening assertion will invoke the
+``_LIBCPP_ASSERTION_HANDLER`` macro upon failure. A vendor may provide a header
+that contains a custom definition of this macro and specify the path to the
+header via the ``LIBCXX_ASSERTION_HANDLER_FILE`` CMake variable. If provided,
+this header will be included by the library and replace the default
+implementation. The header must not include any standard library headers
+(directly or transitively) because doing so will almost always create a circular
+dependency. The ``_LIBCPP_ASSERTION_HANDLER(message)`` macro takes a single
+parameter that contains an error message explaining the hardening failure and
+some details about the source location that triggered it.
When a hardening assertion fails, it means that the program is about to invoke
library undefined behavior. For this reason, the custom assertion handler is
diff --git a/libcxx/docs/ReleaseNotes/18.rst b/libcxx/docs/ReleaseNotes/18.rst
index 9cc024c3d7634e..39ef9afe387562 100644
--- a/libcxx/docs/ReleaseNotes/18.rst
+++ b/libcxx/docs/ReleaseNotes/18.rst
@@ -145,7 +145,7 @@ Deprecations and Removals
Upcoming Deprecations and Removals
----------------------------------
-- ``__libcpp_verbose_abort`` and the ability to override this function will be removed in an upcoming release.
+- The ability to override ``__libcpp_verbose_abort`` will be removed in an upcoming release.
LLVM 19
~~~~~~~
diff --git a/libcxx/test/support/test.support/test_check_assertion.pass.cpp b/libcxx/test/support/test.support/test_check_assertion.pass.cpp
index ce0c30ad4069a3..d1ac6717267f3b 100644
--- a/libcxx/test/support/test.support/test_check_assertion.pass.cpp
+++ b/libcxx/test/support/test.support/test_check_assertion.pass.cpp
@@ -86,7 +86,6 @@ int main(int, char**) {
// Success -- `std::terminate`.
TEST_DEATH_TEST(Outcome::Success, DeathCause::StdTerminate, std::terminate());
- (void)fail_assert;
// Success -- trapping.
TEST_DEATH_TEST(Outcome::Success, DeathCause::Trap, __builtin_trap());
diff --git a/libcxx/vendor/llvm/default_assertion_handler.in b/libcxx/vendor/llvm/default_assertion_handler.in
index 60bbf27489097b..8bc0553c078b34 100644
--- a/libcxx/vendor/llvm/default_assertion_handler.in
+++ b/libcxx/vendor/llvm/default_assertion_handler.in
@@ -23,6 +23,7 @@
#else
+// TODO(hardening): use `__builtin_verbose_trap(message)` once that becomes available.
# define _LIBCPP_ASSERTION_HANDLER(message) ((void)message, __builtin_trap())
#endif // _LIBCPP_HARDENING_MODE == _LIBCPP_HARDENING_MODE_DEBUG
>From eafad536fa977a13ea67ce8c4336327bafcb295c Mon Sep 17 00:00:00 2001
From: Konstantin Varlamov <varconsteq at gmail.com>
Date: Fri, 19 Jan 2024 12:03:42 -0800
Subject: [PATCH 11/11] CI fixes
---
.../libcxx/algorithms/alg.sorting/assert.min.max.pass.cpp | 2 +-
.../alg.sorting/assert.sort.invalid_comparator.pass.cpp | 2 +-
libcxx/test/libcxx/assertions/default_verbose_abort.pass.cpp | 1 +
.../enabling_assertions_enables_extensive_mode.pass.cpp | 5 +++--
libcxx/test/libcxx/assertions/modes/extensive.pass.cpp | 1 -
libcxx/test/libcxx/assertions/modes/fast.pass.cpp | 1 -
.../assertions/modes/override_with_extensive_mode.pass.cpp | 5 +++--
.../libcxx/assertions/modes/override_with_fast_mode.pass.cpp | 5 +++--
.../sequences/array/array.zero/assert.back.pass.cpp | 2 +-
.../sequences/array/array.zero/assert.front.pass.cpp | 2 +-
.../sequences/array/array.zero/assert.subscript.pass.cpp | 2 +-
.../sequences/deque/assert.pop_back.empty.pass.cpp | 2 +-
.../list/list.modifiers/assert.erase_iter.end.pass.cpp | 2 +-
.../list/list.modifiers/assert.pop_back.empty.pass.cpp | 2 +-
.../containers/sequences/vector/assert.back.empty.pass.cpp | 2 +-
.../containers/sequences/vector/assert.cback.empty.pass.cpp | 2 +-
.../containers/sequences/vector/assert.cfront.empty.pass.cpp | 2 +-
.../containers/sequences/vector/assert.cindex.oob.pass.cpp | 2 +-
.../containers/sequences/vector/assert.front.empty.pass.cpp | 2 +-
.../containers/sequences/vector/assert.index.oob.pass.cpp | 2 +-
.../sequences/vector/assert.pop_back.empty.pass.cpp | 2 +-
.../libcxx/containers/unord/unord.map/assert.bucket.pass.cpp | 2 +-
.../containers/unord/unord.map/assert.bucket_size.pass.cpp | 2 +-
.../unord/unord.map/assert.max_load_factor.pass.cpp | 2 +-
.../containers/unord/unord.multimap/assert.bucket.pass.cpp | 2 +-
.../unord/unord.multimap/assert.bucket_size.pass.cpp | 2 +-
.../unord/unord.multimap/assert.max_load_factor.pass.cpp | 2 +-
.../containers/unord/unord.multiset/assert.bucket.pass.cpp | 2 +-
.../unord/unord.multiset/assert.bucket_size.pass.cpp | 2 +-
.../unord/unord.multiset/assert.max_load_factor.pass.cpp | 2 +-
.../libcxx/containers/unord/unord.set/assert.bucket.pass.cpp | 2 +-
.../containers/unord/unord.set/assert.bucket_size.pass.cpp | 2 +-
.../unord/unord.set/assert.max_load_factor.pass.cpp | 2 +-
.../views/mdspan/extents/assert.conversion.pass.cpp | 2 +-
.../views/mdspan/extents/assert.ctor_from_array.pass.cpp | 2 +-
.../views/mdspan/extents/assert.ctor_from_integral.pass.cpp | 2 +-
.../views/mdspan/extents/assert.ctor_from_span.pass.cpp | 2 +-
.../containers/views/mdspan/extents/assert.obs.pass.cpp | 2 +-
.../views/mdspan/layout_left/assert.conversion.pass.cpp | 2 +-
.../views/mdspan/layout_left/assert.ctor.extents.pass.cpp | 2 +-
.../mdspan/layout_left/assert.ctor.layout_right.pass.cpp | 2 +-
.../mdspan/layout_left/assert.ctor.layout_stride.pass.cpp | 2 +-
.../views/mdspan/layout_left/assert.index_operator.pass.cpp | 2 +-
.../views/mdspan/layout_left/assert.stride.pass.cpp | 2 +-
.../views/mdspan/layout_right/assert.conversion.pass.cpp | 2 +-
.../views/mdspan/layout_right/assert.ctor.extents.pass.cpp | 2 +-
.../mdspan/layout_right/assert.ctor.layout_left.pass.cpp | 2 +-
.../mdspan/layout_right/assert.ctor.layout_stride.pass.cpp | 2 +-
.../views/mdspan/layout_right/assert.index_operator.pass.cpp | 2 +-
.../views/mdspan/layout_right/assert.stride.pass.cpp | 2 +-
.../views/mdspan/layout_stride/assert.conversion.pass.cpp | 2 +-
.../assert.ctor.extents_array.non_unique.pass.cpp | 2 +-
.../mdspan/layout_stride/assert.ctor.extents_array.pass.cpp | 2 +-
.../assert.ctor.extents_span.non_unique.pass.cpp | 2 +-
.../mdspan/layout_stride/assert.ctor.extents_span.pass.cpp | 2 +-
.../mdspan/layout_stride/assert.index_operator.pass.cpp | 2 +-
.../views/mdspan/layout_stride/assert.stride.pass.cpp | 2 +-
.../views/mdspan/mdspan/assert.conversion.pass.cpp | 2 +-
.../views/mdspan/mdspan/assert.index_operator.pass.cpp | 2 +-
.../containers/views/mdspan/mdspan/assert.size.pass.cpp | 2 +-
.../views/views.span/span.cons/assert.iter_sent.pass.cpp | 2 +-
.../views/views.span/span.cons/assert.iter_size.pass.cpp | 2 +-
.../views/views.span/span.cons/assert.other_span.pass.cpp | 2 +-
.../views/views.span/span.cons/assert.range.pass.cpp | 2 +-
.../views/views.span/span.elem/assert.back.pass.cpp | 2 +-
.../views/views.span/span.elem/assert.front.pass.cpp | 2 +-
.../views/views.span/span.elem/assert.op_idx.pass.cpp | 2 +-
.../views/views.span/span.sub/assert.first.pass.cpp | 2 +-
.../views/views.span/span.sub/assert.last.pass.cpp | 2 +-
.../views/views.span/span.sub/assert.subspan.pass.cpp | 2 +-
.../filesystems/class.path/path.itr/assert.iterator.pass.cpp | 2 +-
libcxx/test/libcxx/iterators/assert.advance.pass.cpp | 2 +-
libcxx/test/libcxx/iterators/assert.next.pass.cpp | 2 +-
libcxx/test/libcxx/iterators/assert.prev.pass.cpp | 2 +-
.../test/libcxx/iterators/bounded_iter/dereference.pass.cpp | 2 +-
.../predef.iterators/counted.iterator/assert.pass.cpp | 2 +-
.../predef.iterators/iterators.common/assert.pass.cpp | 2 +-
.../range.adaptors/range.chunk.by/assert.begin.pass.cpp | 2 +-
.../range.adaptors/range.chunk.by/assert.find-next.pass.cpp | 2 +-
.../range.adaptors/range.chunk.by/assert.find-prev.pass.cpp | 2 +-
.../range.chunk.by/range.chunk.by.iter/assert.deref.pass.cpp | 2 +-
.../range.chunk.by.iter/assert.increment.pass.cpp | 2 +-
.../range.adaptors/range.drop.while/assert.begin.pass.cpp | 2 +-
.../range.lazy.split.inner/assert.equal.pass.cpp | 2 +-
.../range.lazy.split.outer/assert.equal.pass.cpp | 2 +-
.../strings/basic.string/string.access/assert.back.pass.cpp | 2 +-
.../strings/basic.string/string.access/assert.cback.pass.cpp | 2 +-
.../basic.string/string.access/assert.cfront.pass.cpp | 2 +-
.../basic.string/string.access/assert.cindex.pass.cpp | 2 +-
.../strings/basic.string/string.access/assert.front.pass.cpp | 2 +-
.../strings/basic.string/string.access/assert.index.pass.cpp | 2 +-
.../string.modifiers/assert.erase_iter.null.pass.cpp | 2 +-
.../basic.string/string.modifiers/assert.pop_back.pass.cpp | 2 +-
.../libcxx/strings/string.view/assert.ctor.length.pass.cpp | 2 +-
.../libcxx/strings/string.view/assert.ctor.pointer.pass.cpp | 2 +-
.../futures/futures.promise/assert.set_exception.pass.cpp | 2 +-
.../assert.set_exception_at_thread_exit.pass.cpp | 2 +-
.../test/libcxx/thread/thread.barrier/assert.arrive.pass.cpp | 2 +-
.../test/libcxx/thread/thread.barrier/assert.ctor.pass.cpp | 2 +-
.../thread/thread.latch/assert.arrive_and_wait.pass.cpp | 2 +-
.../libcxx/thread/thread.latch/assert.count_down.pass.cpp | 2 +-
libcxx/test/libcxx/thread/thread.latch/assert.ctor.pass.cpp | 2 +-
.../test/libcxx/thread/thread.semaphore/assert.ctor.pass.cpp | 2 +-
.../libcxx/thread/thread.semaphore/assert.release.pass.cpp | 2 +-
.../utilities/assert.exception_guard.no_exceptions.pass.cpp | 2 +-
.../expected/expected.expected/assert.arrow.pass.cpp | 2 +-
.../expected/expected.expected/assert.deref.pass.cpp | 2 +-
.../expected/expected.expected/assert.error.pass.cpp | 2 +-
.../utilities/expected/expected.void/assert.deref.pass.cpp | 2 +-
.../utilities/expected/expected.void/assert.error.pass.cpp | 2 +-
.../optional.object.observe/assert.dereference.pass.cpp | 2 +-
.../optional.object.observe/assert.op_arrow.pass.cpp | 2 +-
112 files changed, 116 insertions(+), 114 deletions(-)
diff --git a/libcxx/test/libcxx/algorithms/alg.sorting/assert.min.max.pass.cpp b/libcxx/test/libcxx/algorithms/alg.sorting/assert.min.max.pass.cpp
index bd9dfd4549c4e2..7e765d7e846834 100644
--- a/libcxx/test/libcxx/algorithms/alg.sorting/assert.min.max.pass.cpp
+++ b/libcxx/test/libcxx/algorithms/alg.sorting/assert.min.max.pass.cpp
@@ -11,7 +11,7 @@
// REQUIRES: has-unix-headers
// UNSUPPORTED: c++03, c++11, c++14, c++17
// UNSUPPORTED: libcpp-hardening-mode=none
-// XFAIL: availability-verbose_abort-missing
+// XFAIL: libcpp-hardening-mode=debug && availability-verbose_abort-missing
#include <algorithm>
#include <array>
diff --git a/libcxx/test/libcxx/algorithms/alg.sorting/assert.sort.invalid_comparator.pass.cpp b/libcxx/test/libcxx/algorithms/alg.sorting/assert.sort.invalid_comparator.pass.cpp
index 96c2821c4a654c..f90e2a3a1a71fd 100644
--- a/libcxx/test/libcxx/algorithms/alg.sorting/assert.sort.invalid_comparator.pass.cpp
+++ b/libcxx/test/libcxx/algorithms/alg.sorting/assert.sort.invalid_comparator.pass.cpp
@@ -11,7 +11,7 @@
// REQUIRES: has-unix-headers
// UNSUPPORTED: c++03, c++11, c++14, c++17
// UNSUPPORTED: !libcpp-hardening-mode=debug
-// XFAIL: availability-verbose_abort-missing
+// XFAIL: libcpp-hardening-mode=debug && availability-verbose_abort-missing
// ADDITIONAL_COMPILE_FLAGS: -D_LIBCPP_DEBUG_STRICT_WEAK_ORDERING_CHECK
// When the debug mode is enabled, this test fails because we actually catch on the fly that the comparator is not
// a strict-weak ordering before we catch that we'd dereference out-of-bounds inside std::sort, which leads to different
diff --git a/libcxx/test/libcxx/assertions/default_verbose_abort.pass.cpp b/libcxx/test/libcxx/assertions/default_verbose_abort.pass.cpp
index 18cc7a9521e498..0cc4b1e0052267 100644
--- a/libcxx/test/libcxx/assertions/default_verbose_abort.pass.cpp
+++ b/libcxx/test/libcxx/assertions/default_verbose_abort.pass.cpp
@@ -7,6 +7,7 @@
//===----------------------------------------------------------------------===//
// Test that the default verbose termination function aborts the program.
+// XFAIL: availability-verbose_abort-missing
#include <__verbose_abort>
#include <csignal>
diff --git a/libcxx/test/libcxx/assertions/modes/enabling_assertions_enables_extensive_mode.pass.cpp b/libcxx/test/libcxx/assertions/modes/enabling_assertions_enables_extensive_mode.pass.cpp
index a40ae84fa8e85d..a91ba041763749 100644
--- a/libcxx/test/libcxx/assertions/modes/enabling_assertions_enables_extensive_mode.pass.cpp
+++ b/libcxx/test/libcxx/assertions/modes/enabling_assertions_enables_extensive_mode.pass.cpp
@@ -12,8 +12,9 @@
// `check_assertion.h` is only available starting from C++11 and requires Unix headers and regex support.
// UNSUPPORTED: c++03, !has-unix-headers, no-localization
-// The ability to set a custom abort message is required to compare the assertion message.
-// XFAIL: availability-verbose_abort-missing
+// The ability to set a custom abort message is required to compare the assertion message (which only happens in the
+// debug mode).
+// XFAIL: libcpp-hardening-mode=debug && availability-verbose_abort-missing
// Note that GCC doesn't support `-Wno-macro-redefined`.
// ADDITIONAL_COMPILE_FLAGS: -U_LIBCPP_HARDENING_MODE -D_LIBCPP_ENABLE_ASSERTIONS=1
diff --git a/libcxx/test/libcxx/assertions/modes/extensive.pass.cpp b/libcxx/test/libcxx/assertions/modes/extensive.pass.cpp
index e9e494eae341b4..5743f95e472d70 100644
--- a/libcxx/test/libcxx/assertions/modes/extensive.pass.cpp
+++ b/libcxx/test/libcxx/assertions/modes/extensive.pass.cpp
@@ -14,7 +14,6 @@
// UNSUPPORTED: c++03
// `check_assertion.h` requires Unix headers.
// REQUIRES: has-unix-headers
-// XFAIL: availability-verbose_abort-missing
#include <cassert>
#include "check_assertion.h"
diff --git a/libcxx/test/libcxx/assertions/modes/fast.pass.cpp b/libcxx/test/libcxx/assertions/modes/fast.pass.cpp
index 33377f03fe870f..85181859fdad0d 100644
--- a/libcxx/test/libcxx/assertions/modes/fast.pass.cpp
+++ b/libcxx/test/libcxx/assertions/modes/fast.pass.cpp
@@ -14,7 +14,6 @@
// UNSUPPORTED: c++03
// `check_assertion.h` requires Unix headers.
// REQUIRES: has-unix-headers
-// XFAIL: availability-verbose_abort-missing
#include <cassert>
#include "check_assertion.h"
diff --git a/libcxx/test/libcxx/assertions/modes/override_with_extensive_mode.pass.cpp b/libcxx/test/libcxx/assertions/modes/override_with_extensive_mode.pass.cpp
index f5323c671c9b1f..f78d5d70e58904 100644
--- a/libcxx/test/libcxx/assertions/modes/override_with_extensive_mode.pass.cpp
+++ b/libcxx/test/libcxx/assertions/modes/override_with_extensive_mode.pass.cpp
@@ -10,8 +10,9 @@
// `check_assertion.h` is only available starting from C++11 and requires Unix headers and regex support.
// UNSUPPORTED: c++03, !has-unix-headers, no-localization
-// The ability to set a custom abort message is required to compare the assertion message.
-// XFAIL: availability-verbose_abort-missing
+// The ability to set a custom abort message is required to compare the assertion message (which only happens in the
+// debug mode).
+// XFAIL: libcpp-hardening-mode=debug && availability-verbose_abort-missing
// ADDITIONAL_COMPILE_FLAGS: -U_LIBCPP_HARDENING_MODE -D_LIBCPP_HARDENING_MODE=_LIBCPP_HARDENING_MODE_EXTENSIVE
#include <cassert>
diff --git a/libcxx/test/libcxx/assertions/modes/override_with_fast_mode.pass.cpp b/libcxx/test/libcxx/assertions/modes/override_with_fast_mode.pass.cpp
index 5ee22cc45f3bf0..27542ee32bef94 100644
--- a/libcxx/test/libcxx/assertions/modes/override_with_fast_mode.pass.cpp
+++ b/libcxx/test/libcxx/assertions/modes/override_with_fast_mode.pass.cpp
@@ -10,8 +10,9 @@
// `check_assertion.h` is only available starting from C++11 and requires Unix headers and regex support.
// UNSUPPORTED: c++03, !has-unix-headers, no-localization
-// The ability to set a custom abort message is required to compare the assertion message.
-// XFAIL: availability-verbose_abort-missing
+// The ability to set a custom abort message is required to compare the assertion message (which only happens in the
+// debug mode).
+// XFAIL: libcpp-hardening-mode=debug && availability-verbose_abort-missing
// ADDITIONAL_COMPILE_FLAGS: -U_LIBCPP_HARDENING_MODE -D_LIBCPP_HARDENING_MODE=_LIBCPP_HARDENING_MODE_FAST
#include <cassert>
diff --git a/libcxx/test/libcxx/containers/sequences/array/array.zero/assert.back.pass.cpp b/libcxx/test/libcxx/containers/sequences/array/array.zero/assert.back.pass.cpp
index 7bd399fca7e0be..c20b0c9a804f26 100644
--- a/libcxx/test/libcxx/containers/sequences/array/array.zero/assert.back.pass.cpp
+++ b/libcxx/test/libcxx/containers/sequences/array/array.zero/assert.back.pass.cpp
@@ -9,7 +9,7 @@
// REQUIRES: has-unix-headers
// UNSUPPORTED: c++03
// UNSUPPORTED: libcpp-hardening-mode=none
-// XFAIL: availability-verbose_abort-missing
+// XFAIL: libcpp-hardening-mode=debug && availability-verbose_abort-missing
// test that array<T, 0>::back() triggers an assertion
diff --git a/libcxx/test/libcxx/containers/sequences/array/array.zero/assert.front.pass.cpp b/libcxx/test/libcxx/containers/sequences/array/array.zero/assert.front.pass.cpp
index fcfb26ff42726f..1ea0035ee4cc50 100644
--- a/libcxx/test/libcxx/containers/sequences/array/array.zero/assert.front.pass.cpp
+++ b/libcxx/test/libcxx/containers/sequences/array/array.zero/assert.front.pass.cpp
@@ -9,7 +9,7 @@
// REQUIRES: has-unix-headers
// UNSUPPORTED: c++03
// UNSUPPORTED: libcpp-hardening-mode=none
-// XFAIL: availability-verbose_abort-missing
+// XFAIL: libcpp-hardening-mode=debug && availability-verbose_abort-missing
// test that array<T, 0>::back() triggers an assertion
diff --git a/libcxx/test/libcxx/containers/sequences/array/array.zero/assert.subscript.pass.cpp b/libcxx/test/libcxx/containers/sequences/array/array.zero/assert.subscript.pass.cpp
index e221e361405adc..ab65ce223f7c54 100644
--- a/libcxx/test/libcxx/containers/sequences/array/array.zero/assert.subscript.pass.cpp
+++ b/libcxx/test/libcxx/containers/sequences/array/array.zero/assert.subscript.pass.cpp
@@ -9,7 +9,7 @@
// REQUIRES: has-unix-headers
// UNSUPPORTED: c++03
// UNSUPPORTED: libcpp-hardening-mode=none
-// XFAIL: availability-verbose_abort-missing
+// XFAIL: libcpp-hardening-mode=debug && availability-verbose_abort-missing
// test that array<T, 0>::operator[] triggers an assertion
diff --git a/libcxx/test/libcxx/containers/sequences/deque/assert.pop_back.empty.pass.cpp b/libcxx/test/libcxx/containers/sequences/deque/assert.pop_back.empty.pass.cpp
index e0f102b3cc1f82..19cd41f4cf3a2a 100644
--- a/libcxx/test/libcxx/containers/sequences/deque/assert.pop_back.empty.pass.cpp
+++ b/libcxx/test/libcxx/containers/sequences/deque/assert.pop_back.empty.pass.cpp
@@ -13,7 +13,7 @@
// REQUIRES: has-unix-headers
// UNSUPPORTED: c++03
// UNSUPPORTED: libcpp-hardening-mode=none
-// XFAIL: availability-verbose_abort-missing
+// XFAIL: libcpp-hardening-mode=debug && availability-verbose_abort-missing
#include <deque>
diff --git a/libcxx/test/libcxx/containers/sequences/list/list.modifiers/assert.erase_iter.end.pass.cpp b/libcxx/test/libcxx/containers/sequences/list/list.modifiers/assert.erase_iter.end.pass.cpp
index a6471f7389b871..531dd8de399deb 100644
--- a/libcxx/test/libcxx/containers/sequences/list/list.modifiers/assert.erase_iter.end.pass.cpp
+++ b/libcxx/test/libcxx/containers/sequences/list/list.modifiers/assert.erase_iter.end.pass.cpp
@@ -13,7 +13,7 @@
// REQUIRES: has-unix-headers
// UNSUPPORTED: c++03
// UNSUPPORTED: libcpp-hardening-mode=none
-// XFAIL: availability-verbose_abort-missing
+// XFAIL: libcpp-hardening-mode=debug && availability-verbose_abort-missing
#include <list>
diff --git a/libcxx/test/libcxx/containers/sequences/list/list.modifiers/assert.pop_back.empty.pass.cpp b/libcxx/test/libcxx/containers/sequences/list/list.modifiers/assert.pop_back.empty.pass.cpp
index 04e933430a7b05..d7c69991622704 100644
--- a/libcxx/test/libcxx/containers/sequences/list/list.modifiers/assert.pop_back.empty.pass.cpp
+++ b/libcxx/test/libcxx/containers/sequences/list/list.modifiers/assert.pop_back.empty.pass.cpp
@@ -13,7 +13,7 @@
// REQUIRES: has-unix-headers
// UNSUPPORTED: c++03
// UNSUPPORTED: libcpp-hardening-mode=none
-// XFAIL: availability-verbose_abort-missing
+// XFAIL: libcpp-hardening-mode=debug && availability-verbose_abort-missing
#include <list>
#include <cassert>
diff --git a/libcxx/test/libcxx/containers/sequences/vector/assert.back.empty.pass.cpp b/libcxx/test/libcxx/containers/sequences/vector/assert.back.empty.pass.cpp
index b68b5dece68404..169ad1def9e6f6 100644
--- a/libcxx/test/libcxx/containers/sequences/vector/assert.back.empty.pass.cpp
+++ b/libcxx/test/libcxx/containers/sequences/vector/assert.back.empty.pass.cpp
@@ -13,7 +13,7 @@
// REQUIRES: has-unix-headers
// UNSUPPORTED: c++03
// UNSUPPORTED: libcpp-hardening-mode=none
-// XFAIL: availability-verbose_abort-missing
+// XFAIL: libcpp-hardening-mode=debug && availability-verbose_abort-missing
#include <vector>
#include <cassert>
diff --git a/libcxx/test/libcxx/containers/sequences/vector/assert.cback.empty.pass.cpp b/libcxx/test/libcxx/containers/sequences/vector/assert.cback.empty.pass.cpp
index 0c1571f67a53cd..5ceb4a16b93402 100644
--- a/libcxx/test/libcxx/containers/sequences/vector/assert.cback.empty.pass.cpp
+++ b/libcxx/test/libcxx/containers/sequences/vector/assert.cback.empty.pass.cpp
@@ -13,7 +13,7 @@
// REQUIRES: has-unix-headers
// UNSUPPORTED: c++03
// UNSUPPORTED: libcpp-hardening-mode=none
-// XFAIL: availability-verbose_abort-missing
+// XFAIL: libcpp-hardening-mode=debug && availability-verbose_abort-missing
#include <vector>
diff --git a/libcxx/test/libcxx/containers/sequences/vector/assert.cfront.empty.pass.cpp b/libcxx/test/libcxx/containers/sequences/vector/assert.cfront.empty.pass.cpp
index 6d0f4eacf44c0c..20f94f1d3f0fad 100644
--- a/libcxx/test/libcxx/containers/sequences/vector/assert.cfront.empty.pass.cpp
+++ b/libcxx/test/libcxx/containers/sequences/vector/assert.cfront.empty.pass.cpp
@@ -13,7 +13,7 @@
// REQUIRES: has-unix-headers
// UNSUPPORTED: c++03
// UNSUPPORTED: libcpp-hardening-mode=none
-// XFAIL: availability-verbose_abort-missing
+// XFAIL: libcpp-hardening-mode=debug && availability-verbose_abort-missing
#include <vector>
diff --git a/libcxx/test/libcxx/containers/sequences/vector/assert.cindex.oob.pass.cpp b/libcxx/test/libcxx/containers/sequences/vector/assert.cindex.oob.pass.cpp
index 47a531fb3cf756..3a9a7add3e30d0 100644
--- a/libcxx/test/libcxx/containers/sequences/vector/assert.cindex.oob.pass.cpp
+++ b/libcxx/test/libcxx/containers/sequences/vector/assert.cindex.oob.pass.cpp
@@ -13,7 +13,7 @@
// REQUIRES: has-unix-headers
// UNSUPPORTED: c++03
// UNSUPPORTED: libcpp-hardening-mode=none
-// XFAIL: availability-verbose_abort-missing
+// XFAIL: libcpp-hardening-mode=debug && availability-verbose_abort-missing
#include <vector>
#include <cassert>
diff --git a/libcxx/test/libcxx/containers/sequences/vector/assert.front.empty.pass.cpp b/libcxx/test/libcxx/containers/sequences/vector/assert.front.empty.pass.cpp
index 687f8fa8664a6e..85364c778ad64d 100644
--- a/libcxx/test/libcxx/containers/sequences/vector/assert.front.empty.pass.cpp
+++ b/libcxx/test/libcxx/containers/sequences/vector/assert.front.empty.pass.cpp
@@ -13,7 +13,7 @@
// REQUIRES: has-unix-headers
// UNSUPPORTED: c++03
// UNSUPPORTED: libcpp-hardening-mode=none
-// XFAIL: availability-verbose_abort-missing
+// XFAIL: libcpp-hardening-mode=debug && availability-verbose_abort-missing
#include <vector>
#include <cassert>
diff --git a/libcxx/test/libcxx/containers/sequences/vector/assert.index.oob.pass.cpp b/libcxx/test/libcxx/containers/sequences/vector/assert.index.oob.pass.cpp
index 1f3cae3479a1b8..14cb89625f0643 100644
--- a/libcxx/test/libcxx/containers/sequences/vector/assert.index.oob.pass.cpp
+++ b/libcxx/test/libcxx/containers/sequences/vector/assert.index.oob.pass.cpp
@@ -13,7 +13,7 @@
// REQUIRES: has-unix-headers
// UNSUPPORTED: c++03
// UNSUPPORTED: libcpp-hardening-mode=none
-// XFAIL: availability-verbose_abort-missing
+// XFAIL: libcpp-hardening-mode=debug && availability-verbose_abort-missing
#include <vector>
#include <cassert>
diff --git a/libcxx/test/libcxx/containers/sequences/vector/assert.pop_back.empty.pass.cpp b/libcxx/test/libcxx/containers/sequences/vector/assert.pop_back.empty.pass.cpp
index 4ed3fab6d22bb7..ad80be69897edc 100644
--- a/libcxx/test/libcxx/containers/sequences/vector/assert.pop_back.empty.pass.cpp
+++ b/libcxx/test/libcxx/containers/sequences/vector/assert.pop_back.empty.pass.cpp
@@ -13,7 +13,7 @@
// REQUIRES: has-unix-headers
// UNSUPPORTED: c++03
// UNSUPPORTED: libcpp-hardening-mode=none
-// XFAIL: availability-verbose_abort-missing
+// XFAIL: libcpp-hardening-mode=debug && availability-verbose_abort-missing
#include <vector>
diff --git a/libcxx/test/libcxx/containers/unord/unord.map/assert.bucket.pass.cpp b/libcxx/test/libcxx/containers/unord/unord.map/assert.bucket.pass.cpp
index 51718c013ba560..8d23673dfc50f2 100644
--- a/libcxx/test/libcxx/containers/unord/unord.map/assert.bucket.pass.cpp
+++ b/libcxx/test/libcxx/containers/unord/unord.map/assert.bucket.pass.cpp
@@ -13,7 +13,7 @@
// REQUIRES: has-unix-headers
// UNSUPPORTED: c++03
// REQUIRES: libcpp-hardening-mode={{extensive|debug}}
-// XFAIL: availability-verbose_abort-missing
+// XFAIL: libcpp-hardening-mode=debug && availability-verbose_abort-missing
#include <unordered_map>
#include <string>
diff --git a/libcxx/test/libcxx/containers/unord/unord.map/assert.bucket_size.pass.cpp b/libcxx/test/libcxx/containers/unord/unord.map/assert.bucket_size.pass.cpp
index de6aa442c6b3ba..0a0bb888182e9e 100644
--- a/libcxx/test/libcxx/containers/unord/unord.map/assert.bucket_size.pass.cpp
+++ b/libcxx/test/libcxx/containers/unord/unord.map/assert.bucket_size.pass.cpp
@@ -17,7 +17,7 @@
// REQUIRES: has-unix-headers
// UNSUPPORTED: c++03
// REQUIRES: libcpp-hardening-mode={{extensive|debug}}
-// XFAIL: availability-verbose_abort-missing
+// XFAIL: libcpp-hardening-mode=debug && availability-verbose_abort-missing
#include <unordered_map>
#include <string>
diff --git a/libcxx/test/libcxx/containers/unord/unord.map/assert.max_load_factor.pass.cpp b/libcxx/test/libcxx/containers/unord/unord.map/assert.max_load_factor.pass.cpp
index 7b6a83559f9ee1..452a3ae8c3818f 100644
--- a/libcxx/test/libcxx/containers/unord/unord.map/assert.max_load_factor.pass.cpp
+++ b/libcxx/test/libcxx/containers/unord/unord.map/assert.max_load_factor.pass.cpp
@@ -18,7 +18,7 @@
// REQUIRES: has-unix-headers
// UNSUPPORTED: c++03
// REQUIRES: libcpp-hardening-mode={{extensive|debug}}
-// XFAIL: availability-verbose_abort-missing
+// XFAIL: libcpp-hardening-mode=debug && availability-verbose_abort-missing
#include <unordered_map>
#include <string>
diff --git a/libcxx/test/libcxx/containers/unord/unord.multimap/assert.bucket.pass.cpp b/libcxx/test/libcxx/containers/unord/unord.multimap/assert.bucket.pass.cpp
index 2b2859c1e19407..ec3892f444cd6b 100644
--- a/libcxx/test/libcxx/containers/unord/unord.multimap/assert.bucket.pass.cpp
+++ b/libcxx/test/libcxx/containers/unord/unord.multimap/assert.bucket.pass.cpp
@@ -17,7 +17,7 @@
// REQUIRES: has-unix-headers
// UNSUPPORTED: c++03
// REQUIRES: libcpp-hardening-mode={{extensive|debug}}
-// XFAIL: availability-verbose_abort-missing
+// XFAIL: libcpp-hardening-mode=debug && availability-verbose_abort-missing
#include <unordered_map>
#include <string>
diff --git a/libcxx/test/libcxx/containers/unord/unord.multimap/assert.bucket_size.pass.cpp b/libcxx/test/libcxx/containers/unord/unord.multimap/assert.bucket_size.pass.cpp
index 6100ef37a33b11..ea5904b94019eb 100644
--- a/libcxx/test/libcxx/containers/unord/unord.multimap/assert.bucket_size.pass.cpp
+++ b/libcxx/test/libcxx/containers/unord/unord.multimap/assert.bucket_size.pass.cpp
@@ -17,7 +17,7 @@
// REQUIRES: has-unix-headers
// UNSUPPORTED: c++03
// REQUIRES: libcpp-hardening-mode={{extensive|debug}}
-// XFAIL: availability-verbose_abort-missing
+// XFAIL: libcpp-hardening-mode=debug && availability-verbose_abort-missing
#include <unordered_map>
#include <string>
diff --git a/libcxx/test/libcxx/containers/unord/unord.multimap/assert.max_load_factor.pass.cpp b/libcxx/test/libcxx/containers/unord/unord.multimap/assert.max_load_factor.pass.cpp
index 8c80821b823d44..65f7c91d293d6c 100644
--- a/libcxx/test/libcxx/containers/unord/unord.multimap/assert.max_load_factor.pass.cpp
+++ b/libcxx/test/libcxx/containers/unord/unord.multimap/assert.max_load_factor.pass.cpp
@@ -18,7 +18,7 @@
// REQUIRES: has-unix-headers
// UNSUPPORTED: c++03
// REQUIRES: libcpp-hardening-mode={{extensive|debug}}
-// XFAIL: availability-verbose_abort-missing
+// XFAIL: libcpp-hardening-mode=debug && availability-verbose_abort-missing
#include <unordered_map>
#include <string>
diff --git a/libcxx/test/libcxx/containers/unord/unord.multiset/assert.bucket.pass.cpp b/libcxx/test/libcxx/containers/unord/unord.multiset/assert.bucket.pass.cpp
index 40c68fd6c0c09b..49fdb723b42301 100644
--- a/libcxx/test/libcxx/containers/unord/unord.multiset/assert.bucket.pass.cpp
+++ b/libcxx/test/libcxx/containers/unord/unord.multiset/assert.bucket.pass.cpp
@@ -17,7 +17,7 @@
// REQUIRES: has-unix-headers
// UNSUPPORTED: c++03
// REQUIRES: libcpp-hardening-mode={{extensive|debug}}
-// XFAIL: availability-verbose_abort-missing
+// XFAIL: libcpp-hardening-mode=debug && availability-verbose_abort-missing
#include <unordered_set>
diff --git a/libcxx/test/libcxx/containers/unord/unord.multiset/assert.bucket_size.pass.cpp b/libcxx/test/libcxx/containers/unord/unord.multiset/assert.bucket_size.pass.cpp
index 8599b53ae30c8b..5709fd1e30d9ab 100644
--- a/libcxx/test/libcxx/containers/unord/unord.multiset/assert.bucket_size.pass.cpp
+++ b/libcxx/test/libcxx/containers/unord/unord.multiset/assert.bucket_size.pass.cpp
@@ -17,7 +17,7 @@
// REQUIRES: has-unix-headers
// UNSUPPORTED: c++03
// REQUIRES: libcpp-hardening-mode={{extensive|debug}}
-// XFAIL: availability-verbose_abort-missing
+// XFAIL: libcpp-hardening-mode=debug && availability-verbose_abort-missing
#include <unordered_set>
diff --git a/libcxx/test/libcxx/containers/unord/unord.multiset/assert.max_load_factor.pass.cpp b/libcxx/test/libcxx/containers/unord/unord.multiset/assert.max_load_factor.pass.cpp
index 0dedebed4acfcf..c54bb833e72403 100644
--- a/libcxx/test/libcxx/containers/unord/unord.multiset/assert.max_load_factor.pass.cpp
+++ b/libcxx/test/libcxx/containers/unord/unord.multiset/assert.max_load_factor.pass.cpp
@@ -18,7 +18,7 @@
// REQUIRES: has-unix-headers
// UNSUPPORTED: c++03
// REQUIRES: libcpp-hardening-mode={{extensive|debug}}
-// XFAIL: availability-verbose_abort-missing
+// XFAIL: libcpp-hardening-mode=debug && availability-verbose_abort-missing
#include <unordered_set>
diff --git a/libcxx/test/libcxx/containers/unord/unord.set/assert.bucket.pass.cpp b/libcxx/test/libcxx/containers/unord/unord.set/assert.bucket.pass.cpp
index d5a3cd9a5c1b30..c0bfb00efc68ae 100644
--- a/libcxx/test/libcxx/containers/unord/unord.set/assert.bucket.pass.cpp
+++ b/libcxx/test/libcxx/containers/unord/unord.set/assert.bucket.pass.cpp
@@ -17,7 +17,7 @@
// REQUIRES: has-unix-headers
// UNSUPPORTED: c++03
// REQUIRES: libcpp-hardening-mode={{extensive|debug}}
-// XFAIL: availability-verbose_abort-missing
+// XFAIL: libcpp-hardening-mode=debug && availability-verbose_abort-missing
#include <unordered_set>
diff --git a/libcxx/test/libcxx/containers/unord/unord.set/assert.bucket_size.pass.cpp b/libcxx/test/libcxx/containers/unord/unord.set/assert.bucket_size.pass.cpp
index f8f5feea48aabf..3e25b448cb8726 100644
--- a/libcxx/test/libcxx/containers/unord/unord.set/assert.bucket_size.pass.cpp
+++ b/libcxx/test/libcxx/containers/unord/unord.set/assert.bucket_size.pass.cpp
@@ -17,7 +17,7 @@
// REQUIRES: has-unix-headers
// UNSUPPORTED: c++03
// REQUIRES: libcpp-hardening-mode={{extensive|debug}}
-// XFAIL: availability-verbose_abort-missing
+// XFAIL: libcpp-hardening-mode=debug && availability-verbose_abort-missing
#include <unordered_set>
diff --git a/libcxx/test/libcxx/containers/unord/unord.set/assert.max_load_factor.pass.cpp b/libcxx/test/libcxx/containers/unord/unord.set/assert.max_load_factor.pass.cpp
index 002e5f3962146a..ec1f1f3bd5ce17 100644
--- a/libcxx/test/libcxx/containers/unord/unord.set/assert.max_load_factor.pass.cpp
+++ b/libcxx/test/libcxx/containers/unord/unord.set/assert.max_load_factor.pass.cpp
@@ -18,7 +18,7 @@
// REQUIRES: has-unix-headers
// UNSUPPORTED: c++03
// REQUIRES: libcpp-hardening-mode={{extensive|debug}}
-// XFAIL: availability-verbose_abort-missing
+// XFAIL: libcpp-hardening-mode=debug && availability-verbose_abort-missing
#include <unordered_set>
diff --git a/libcxx/test/libcxx/containers/views/mdspan/extents/assert.conversion.pass.cpp b/libcxx/test/libcxx/containers/views/mdspan/extents/assert.conversion.pass.cpp
index e8cde6bf8856c8..03ed1f78b778b4 100644
--- a/libcxx/test/libcxx/containers/views/mdspan/extents/assert.conversion.pass.cpp
+++ b/libcxx/test/libcxx/containers/views/mdspan/extents/assert.conversion.pass.cpp
@@ -7,7 +7,7 @@
// REQUIRES: has-unix-headers
// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
// UNSUPPORTED: libcpp-hardening-mode=none
-// XFAIL: availability-verbose_abort-missing
+// XFAIL: libcpp-hardening-mode=debug && availability-verbose_abort-missing
// <mdspan>
diff --git a/libcxx/test/libcxx/containers/views/mdspan/extents/assert.ctor_from_array.pass.cpp b/libcxx/test/libcxx/containers/views/mdspan/extents/assert.ctor_from_array.pass.cpp
index 886375e54ca3ca..906a6ec87bd446 100644
--- a/libcxx/test/libcxx/containers/views/mdspan/extents/assert.ctor_from_array.pass.cpp
+++ b/libcxx/test/libcxx/containers/views/mdspan/extents/assert.ctor_from_array.pass.cpp
@@ -7,7 +7,7 @@
// REQUIRES: has-unix-headers
// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
// UNSUPPORTED: libcpp-hardening-mode=none
-// XFAIL: availability-verbose_abort-missing
+// XFAIL: libcpp-hardening-mode=debug && availability-verbose_abort-missing
// <mdspan>
diff --git a/libcxx/test/libcxx/containers/views/mdspan/extents/assert.ctor_from_integral.pass.cpp b/libcxx/test/libcxx/containers/views/mdspan/extents/assert.ctor_from_integral.pass.cpp
index e03bb28ba1cfba..af484a300ea8b3 100644
--- a/libcxx/test/libcxx/containers/views/mdspan/extents/assert.ctor_from_integral.pass.cpp
+++ b/libcxx/test/libcxx/containers/views/mdspan/extents/assert.ctor_from_integral.pass.cpp
@@ -7,7 +7,7 @@
// REQUIRES: has-unix-headers
// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
// UNSUPPORTED: libcpp-hardening-mode=none
-// XFAIL: availability-verbose_abort-missing
+// XFAIL: libcpp-hardening-mode=debug && availability-verbose_abort-missing
// <mdspan>
diff --git a/libcxx/test/libcxx/containers/views/mdspan/extents/assert.ctor_from_span.pass.cpp b/libcxx/test/libcxx/containers/views/mdspan/extents/assert.ctor_from_span.pass.cpp
index d2e1910b194623..f09515cf1142d1 100644
--- a/libcxx/test/libcxx/containers/views/mdspan/extents/assert.ctor_from_span.pass.cpp
+++ b/libcxx/test/libcxx/containers/views/mdspan/extents/assert.ctor_from_span.pass.cpp
@@ -7,7 +7,7 @@
// REQUIRES: has-unix-headers
// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
// UNSUPPORTED: libcpp-hardening-mode=none
-// XFAIL: availability-verbose_abort-missing
+// XFAIL: libcpp-hardening-mode=debug && availability-verbose_abort-missing
// Test construction from span:
//
diff --git a/libcxx/test/libcxx/containers/views/mdspan/extents/assert.obs.pass.cpp b/libcxx/test/libcxx/containers/views/mdspan/extents/assert.obs.pass.cpp
index 44e6d48e9e1780..c473879d87b718 100644
--- a/libcxx/test/libcxx/containers/views/mdspan/extents/assert.obs.pass.cpp
+++ b/libcxx/test/libcxx/containers/views/mdspan/extents/assert.obs.pass.cpp
@@ -7,7 +7,7 @@
// REQUIRES: has-unix-headers
// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
// UNSUPPORTED: libcpp-hardening-mode=none
-// XFAIL: availability-verbose_abort-missing
+// XFAIL: libcpp-hardening-mode=debug && availability-verbose_abort-missing
// <mdspan>
diff --git a/libcxx/test/libcxx/containers/views/mdspan/layout_left/assert.conversion.pass.cpp b/libcxx/test/libcxx/containers/views/mdspan/layout_left/assert.conversion.pass.cpp
index 94d49f13e9b8a5..2cdfa2667cfd46 100644
--- a/libcxx/test/libcxx/containers/views/mdspan/layout_left/assert.conversion.pass.cpp
+++ b/libcxx/test/libcxx/containers/views/mdspan/layout_left/assert.conversion.pass.cpp
@@ -9,7 +9,7 @@
// REQUIRES: has-unix-headers
// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
// UNSUPPORTED: libcpp-hardening-mode=none
-// XFAIL: availability-verbose_abort-missing
+// XFAIL: libcpp-hardening-mode=debug && availability-verbose_abort-missing
// <mdspan>
diff --git a/libcxx/test/libcxx/containers/views/mdspan/layout_left/assert.ctor.extents.pass.cpp b/libcxx/test/libcxx/containers/views/mdspan/layout_left/assert.ctor.extents.pass.cpp
index e73a167a51be3d..6ac7411f1df014 100644
--- a/libcxx/test/libcxx/containers/views/mdspan/layout_left/assert.ctor.extents.pass.cpp
+++ b/libcxx/test/libcxx/containers/views/mdspan/layout_left/assert.ctor.extents.pass.cpp
@@ -9,7 +9,7 @@
// REQUIRES: has-unix-headers
// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
// UNSUPPORTED: libcpp-hardening-mode=none
-// XFAIL: availability-verbose_abort-missing
+// XFAIL: libcpp-hardening-mode=debug && availability-verbose_abort-missing
// <mdspan>
diff --git a/libcxx/test/libcxx/containers/views/mdspan/layout_left/assert.ctor.layout_right.pass.cpp b/libcxx/test/libcxx/containers/views/mdspan/layout_left/assert.ctor.layout_right.pass.cpp
index d11cf9c2362dde..ceb3242beb9c2a 100644
--- a/libcxx/test/libcxx/containers/views/mdspan/layout_left/assert.ctor.layout_right.pass.cpp
+++ b/libcxx/test/libcxx/containers/views/mdspan/layout_left/assert.ctor.layout_right.pass.cpp
@@ -9,7 +9,7 @@
// REQUIRES: has-unix-headers
// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
// UNSUPPORTED: libcpp-hardening-mode=none
-// XFAIL: availability-verbose_abort-missing
+// XFAIL: libcpp-hardening-mode=debug && availability-verbose_abort-missing
// <mdspan>
diff --git a/libcxx/test/libcxx/containers/views/mdspan/layout_left/assert.ctor.layout_stride.pass.cpp b/libcxx/test/libcxx/containers/views/mdspan/layout_left/assert.ctor.layout_stride.pass.cpp
index 60c08a86d20036..cc9358c853db41 100644
--- a/libcxx/test/libcxx/containers/views/mdspan/layout_left/assert.ctor.layout_stride.pass.cpp
+++ b/libcxx/test/libcxx/containers/views/mdspan/layout_left/assert.ctor.layout_stride.pass.cpp
@@ -9,7 +9,7 @@
// REQUIRES: has-unix-headers
// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
// UNSUPPORTED: libcpp-hardening-mode=none
-// XFAIL: availability-verbose_abort-missing
+// XFAIL: libcpp-hardening-mode=debug && availability-verbose_abort-missing
// ADDITIONAL_COMPILE_FLAGS: -Wno-ctad-maybe-unsupported
// FIXME: https://github.com/llvm/llvm-project/issues/64719
diff --git a/libcxx/test/libcxx/containers/views/mdspan/layout_left/assert.index_operator.pass.cpp b/libcxx/test/libcxx/containers/views/mdspan/layout_left/assert.index_operator.pass.cpp
index c514a532a1a0d3..79e424fbb52cbf 100644
--- a/libcxx/test/libcxx/containers/views/mdspan/layout_left/assert.index_operator.pass.cpp
+++ b/libcxx/test/libcxx/containers/views/mdspan/layout_left/assert.index_operator.pass.cpp
@@ -9,7 +9,7 @@
// REQUIRES: has-unix-headers
// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
// REQUIRES: libcpp-hardening-mode={{extensive|debug}}
-// XFAIL: availability-verbose_abort-missing
+// XFAIL: libcpp-hardening-mode=debug && availability-verbose_abort-missing
// <mdspan>
diff --git a/libcxx/test/libcxx/containers/views/mdspan/layout_left/assert.stride.pass.cpp b/libcxx/test/libcxx/containers/views/mdspan/layout_left/assert.stride.pass.cpp
index e54cf8678ea716..61a5149c6881a3 100644
--- a/libcxx/test/libcxx/containers/views/mdspan/layout_left/assert.stride.pass.cpp
+++ b/libcxx/test/libcxx/containers/views/mdspan/layout_left/assert.stride.pass.cpp
@@ -9,7 +9,7 @@
// REQUIRES: has-unix-headers
// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
// UNSUPPORTED: libcpp-hardening-mode=none
-// XFAIL: availability-verbose_abort-missing
+// XFAIL: libcpp-hardening-mode=debug && availability-verbose_abort-missing
// <mdspan>
diff --git a/libcxx/test/libcxx/containers/views/mdspan/layout_right/assert.conversion.pass.cpp b/libcxx/test/libcxx/containers/views/mdspan/layout_right/assert.conversion.pass.cpp
index f3ee1a63be3685..4695ea834692ec 100644
--- a/libcxx/test/libcxx/containers/views/mdspan/layout_right/assert.conversion.pass.cpp
+++ b/libcxx/test/libcxx/containers/views/mdspan/layout_right/assert.conversion.pass.cpp
@@ -9,7 +9,7 @@
// REQUIRES: has-unix-headers
// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
// UNSUPPORTED: libcpp-hardening-mode=none
-// XFAIL: availability-verbose_abort-missing
+// XFAIL: libcpp-hardening-mode=debug && availability-verbose_abort-missing
// <mdspan>
diff --git a/libcxx/test/libcxx/containers/views/mdspan/layout_right/assert.ctor.extents.pass.cpp b/libcxx/test/libcxx/containers/views/mdspan/layout_right/assert.ctor.extents.pass.cpp
index 824c0b0f5793bc..797a8e3845c2f7 100644
--- a/libcxx/test/libcxx/containers/views/mdspan/layout_right/assert.ctor.extents.pass.cpp
+++ b/libcxx/test/libcxx/containers/views/mdspan/layout_right/assert.ctor.extents.pass.cpp
@@ -9,7 +9,7 @@
// REQUIRES: has-unix-headers
// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
// UNSUPPORTED: libcpp-hardening-mode=none
-// XFAIL: availability-verbose_abort-missing
+// XFAIL: libcpp-hardening-mode=debug && availability-verbose_abort-missing
// <mdspan>
diff --git a/libcxx/test/libcxx/containers/views/mdspan/layout_right/assert.ctor.layout_left.pass.cpp b/libcxx/test/libcxx/containers/views/mdspan/layout_right/assert.ctor.layout_left.pass.cpp
index 29903595a2a7f0..e4044a94b7f68d 100644
--- a/libcxx/test/libcxx/containers/views/mdspan/layout_right/assert.ctor.layout_left.pass.cpp
+++ b/libcxx/test/libcxx/containers/views/mdspan/layout_right/assert.ctor.layout_left.pass.cpp
@@ -9,7 +9,7 @@
// REQUIRES: has-unix-headers
// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
// UNSUPPORTED: libcpp-hardening-mode=none
-// XFAIL: availability-verbose_abort-missing
+// XFAIL: libcpp-hardening-mode=debug && availability-verbose_abort-missing
// <mdspan>
diff --git a/libcxx/test/libcxx/containers/views/mdspan/layout_right/assert.ctor.layout_stride.pass.cpp b/libcxx/test/libcxx/containers/views/mdspan/layout_right/assert.ctor.layout_stride.pass.cpp
index a14459823ff6a2..18d974333a5800 100644
--- a/libcxx/test/libcxx/containers/views/mdspan/layout_right/assert.ctor.layout_stride.pass.cpp
+++ b/libcxx/test/libcxx/containers/views/mdspan/layout_right/assert.ctor.layout_stride.pass.cpp
@@ -9,7 +9,7 @@
// REQUIRES: has-unix-headers
// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
// UNSUPPORTED: libcpp-hardening-mode=none
-// XFAIL: availability-verbose_abort-missing
+// XFAIL: libcpp-hardening-mode=debug && availability-verbose_abort-missing
// ADDITIONAL_COMPILE_FLAGS: -Wno-ctad-maybe-unsupported
// FIXME: https://github.com/llvm/llvm-project/issues/64719
diff --git a/libcxx/test/libcxx/containers/views/mdspan/layout_right/assert.index_operator.pass.cpp b/libcxx/test/libcxx/containers/views/mdspan/layout_right/assert.index_operator.pass.cpp
index 756234f157f2c5..7fae6f87caf7ce 100644
--- a/libcxx/test/libcxx/containers/views/mdspan/layout_right/assert.index_operator.pass.cpp
+++ b/libcxx/test/libcxx/containers/views/mdspan/layout_right/assert.index_operator.pass.cpp
@@ -9,7 +9,7 @@
// REQUIRES: has-unix-headers
// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
// REQUIRES: libcpp-hardening-mode={{extensive|debug}}
-// XFAIL: availability-verbose_abort-missing
+// XFAIL: libcpp-hardening-mode=debug && availability-verbose_abort-missing
// <mdspan>
diff --git a/libcxx/test/libcxx/containers/views/mdspan/layout_right/assert.stride.pass.cpp b/libcxx/test/libcxx/containers/views/mdspan/layout_right/assert.stride.pass.cpp
index 9cc5ad72f9349c..8e3049c4736f0a 100644
--- a/libcxx/test/libcxx/containers/views/mdspan/layout_right/assert.stride.pass.cpp
+++ b/libcxx/test/libcxx/containers/views/mdspan/layout_right/assert.stride.pass.cpp
@@ -9,7 +9,7 @@
// REQUIRES: has-unix-headers
// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
// UNSUPPORTED: libcpp-hardening-mode=none
-// XFAIL: availability-verbose_abort-missing
+// XFAIL: libcpp-hardening-mode=debug && availability-verbose_abort-missing
// <mdspan>
diff --git a/libcxx/test/libcxx/containers/views/mdspan/layout_stride/assert.conversion.pass.cpp b/libcxx/test/libcxx/containers/views/mdspan/layout_stride/assert.conversion.pass.cpp
index c6d3e4fe97f615..81f6321ef519cd 100644
--- a/libcxx/test/libcxx/containers/views/mdspan/layout_stride/assert.conversion.pass.cpp
+++ b/libcxx/test/libcxx/containers/views/mdspan/layout_stride/assert.conversion.pass.cpp
@@ -9,7 +9,7 @@
// REQUIRES: has-unix-headers
// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
// UNSUPPORTED: libcpp-hardening-mode=none
-// XFAIL: availability-verbose_abort-missing
+// XFAIL: libcpp-hardening-mode=debug && availability-verbose_abort-missing
// XFAIL: target=powerpc{{.*}}le-unknown-linux-gnu
// <mdspan>
diff --git a/libcxx/test/libcxx/containers/views/mdspan/layout_stride/assert.ctor.extents_array.non_unique.pass.cpp b/libcxx/test/libcxx/containers/views/mdspan/layout_stride/assert.ctor.extents_array.non_unique.pass.cpp
index 34b333ec3d1451..97a6d56e4f8397 100644
--- a/libcxx/test/libcxx/containers/views/mdspan/layout_stride/assert.ctor.extents_array.non_unique.pass.cpp
+++ b/libcxx/test/libcxx/containers/views/mdspan/layout_stride/assert.ctor.extents_array.non_unique.pass.cpp
@@ -9,7 +9,7 @@
// REQUIRES: has-unix-headers
// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
// UNSUPPORTED: !libcpp-hardening-mode=debug
-// XFAIL: availability-verbose_abort-missing
+// XFAIL: libcpp-hardening-mode=debug && availability-verbose_abort-missing
// <mdspan>
diff --git a/libcxx/test/libcxx/containers/views/mdspan/layout_stride/assert.ctor.extents_array.pass.cpp b/libcxx/test/libcxx/containers/views/mdspan/layout_stride/assert.ctor.extents_array.pass.cpp
index eab1c67ed69793..31b38bd8079cef 100644
--- a/libcxx/test/libcxx/containers/views/mdspan/layout_stride/assert.ctor.extents_array.pass.cpp
+++ b/libcxx/test/libcxx/containers/views/mdspan/layout_stride/assert.ctor.extents_array.pass.cpp
@@ -9,7 +9,7 @@
// REQUIRES: has-unix-headers
// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
// UNSUPPORTED: libcpp-hardening-mode=none
-// XFAIL: availability-verbose_abort-missing
+// XFAIL: libcpp-hardening-mode=debug && availability-verbose_abort-missing
// <mdspan>
diff --git a/libcxx/test/libcxx/containers/views/mdspan/layout_stride/assert.ctor.extents_span.non_unique.pass.cpp b/libcxx/test/libcxx/containers/views/mdspan/layout_stride/assert.ctor.extents_span.non_unique.pass.cpp
index 9e1de537682d8d..fd0701e9ee3a7a 100644
--- a/libcxx/test/libcxx/containers/views/mdspan/layout_stride/assert.ctor.extents_span.non_unique.pass.cpp
+++ b/libcxx/test/libcxx/containers/views/mdspan/layout_stride/assert.ctor.extents_span.non_unique.pass.cpp
@@ -9,7 +9,7 @@
// REQUIRES: has-unix-headers
// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
// UNSUPPORTED: !libcpp-hardening-mode=debug
-// XFAIL: availability-verbose_abort-missing
+// XFAIL: libcpp-hardening-mode=debug && availability-verbose_abort-missing
// <mdspan>
diff --git a/libcxx/test/libcxx/containers/views/mdspan/layout_stride/assert.ctor.extents_span.pass.cpp b/libcxx/test/libcxx/containers/views/mdspan/layout_stride/assert.ctor.extents_span.pass.cpp
index 3b7338449a7f6d..4cd0d8ff896ab6 100644
--- a/libcxx/test/libcxx/containers/views/mdspan/layout_stride/assert.ctor.extents_span.pass.cpp
+++ b/libcxx/test/libcxx/containers/views/mdspan/layout_stride/assert.ctor.extents_span.pass.cpp
@@ -9,7 +9,7 @@
// REQUIRES: has-unix-headers
// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
// UNSUPPORTED: libcpp-hardening-mode=none
-// XFAIL: availability-verbose_abort-missing
+// XFAIL: libcpp-hardening-mode=debug && availability-verbose_abort-missing
// <mdspan>
diff --git a/libcxx/test/libcxx/containers/views/mdspan/layout_stride/assert.index_operator.pass.cpp b/libcxx/test/libcxx/containers/views/mdspan/layout_stride/assert.index_operator.pass.cpp
index f507b14ca45ebf..b5244a60af0f70 100644
--- a/libcxx/test/libcxx/containers/views/mdspan/layout_stride/assert.index_operator.pass.cpp
+++ b/libcxx/test/libcxx/containers/views/mdspan/layout_stride/assert.index_operator.pass.cpp
@@ -9,7 +9,7 @@
// REQUIRES: has-unix-headers
// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
// UNSUPPORTED: !libcpp-hardening-mode=debug
-// XFAIL: availability-verbose_abort-missing
+// XFAIL: libcpp-hardening-mode=debug && availability-verbose_abort-missing
// <mdspan>
diff --git a/libcxx/test/libcxx/containers/views/mdspan/layout_stride/assert.stride.pass.cpp b/libcxx/test/libcxx/containers/views/mdspan/layout_stride/assert.stride.pass.cpp
index 5ae141389da4ec..ee2b731da203b2 100644
--- a/libcxx/test/libcxx/containers/views/mdspan/layout_stride/assert.stride.pass.cpp
+++ b/libcxx/test/libcxx/containers/views/mdspan/layout_stride/assert.stride.pass.cpp
@@ -9,7 +9,7 @@
// REQUIRES: has-unix-headers
// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
// UNSUPPORTED: libcpp-hardening-mode=none
-// XFAIL: availability-verbose_abort-missing
+// XFAIL: libcpp-hardening-mode=debug && availability-verbose_abort-missing
// <mdspan>
diff --git a/libcxx/test/libcxx/containers/views/mdspan/mdspan/assert.conversion.pass.cpp b/libcxx/test/libcxx/containers/views/mdspan/mdspan/assert.conversion.pass.cpp
index 860bf19af45ca2..53aec7bb714ea7 100644
--- a/libcxx/test/libcxx/containers/views/mdspan/mdspan/assert.conversion.pass.cpp
+++ b/libcxx/test/libcxx/containers/views/mdspan/mdspan/assert.conversion.pass.cpp
@@ -7,7 +7,7 @@
// REQUIRES: has-unix-headers
// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
// UNSUPPORTED: libcpp-hardening-mode=none
-// XFAIL: availability-verbose_abort-missing
+// XFAIL: libcpp-hardening-mode=debug && availability-verbose_abort-missing
// <mdspan>
diff --git a/libcxx/test/libcxx/containers/views/mdspan/mdspan/assert.index_operator.pass.cpp b/libcxx/test/libcxx/containers/views/mdspan/mdspan/assert.index_operator.pass.cpp
index 174bddb56d53c8..9dd957986f14d2 100644
--- a/libcxx/test/libcxx/containers/views/mdspan/mdspan/assert.index_operator.pass.cpp
+++ b/libcxx/test/libcxx/containers/views/mdspan/mdspan/assert.index_operator.pass.cpp
@@ -9,7 +9,7 @@
// REQUIRES: has-unix-headers
// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
// UNSUPPORTED: libcpp-hardening-mode=none
-// XFAIL: availability-verbose_abort-missing
+// XFAIL: libcpp-hardening-mode=debug && availability-verbose_abort-missing
// <mdspan>
diff --git a/libcxx/test/libcxx/containers/views/mdspan/mdspan/assert.size.pass.cpp b/libcxx/test/libcxx/containers/views/mdspan/mdspan/assert.size.pass.cpp
index ee3114e228a0d8..5682de61fbb329 100644
--- a/libcxx/test/libcxx/containers/views/mdspan/mdspan/assert.size.pass.cpp
+++ b/libcxx/test/libcxx/containers/views/mdspan/mdspan/assert.size.pass.cpp
@@ -7,7 +7,7 @@
// REQUIRES: has-unix-headers
// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
// REQUIRES: libcpp-hardening-mode={{extensive|debug}}
-// XFAIL: availability-verbose_abort-missing
+// XFAIL: libcpp-hardening-mode=debug && availability-verbose_abort-missing
// <mdspan>
diff --git a/libcxx/test/libcxx/containers/views/views.span/span.cons/assert.iter_sent.pass.cpp b/libcxx/test/libcxx/containers/views/views.span/span.cons/assert.iter_sent.pass.cpp
index c268ae51e79ac7..fa2a98e33b8f0e 100644
--- a/libcxx/test/libcxx/containers/views/views.span/span.cons/assert.iter_sent.pass.cpp
+++ b/libcxx/test/libcxx/containers/views/views.span/span.cons/assert.iter_sent.pass.cpp
@@ -20,7 +20,7 @@
// REQUIRES: has-unix-headers
// UNSUPPORTED: libcpp-hardening-mode=none
-// XFAIL: availability-verbose_abort-missing
+// XFAIL: libcpp-hardening-mode=debug && availability-verbose_abort-missing
#include <array>
#include <span>
diff --git a/libcxx/test/libcxx/containers/views/views.span/span.cons/assert.iter_size.pass.cpp b/libcxx/test/libcxx/containers/views/views.span/span.cons/assert.iter_size.pass.cpp
index 3c800e9f2fdf9e..4461bad8ff5047 100644
--- a/libcxx/test/libcxx/containers/views/views.span/span.cons/assert.iter_size.pass.cpp
+++ b/libcxx/test/libcxx/containers/views/views.span/span.cons/assert.iter_size.pass.cpp
@@ -17,7 +17,7 @@
// REQUIRES: has-unix-headers
// UNSUPPORTED: libcpp-hardening-mode=none
-// XFAIL: availability-verbose_abort-missing
+// XFAIL: libcpp-hardening-mode=debug && availability-verbose_abort-missing
#include <array>
#include <span>
diff --git a/libcxx/test/libcxx/containers/views/views.span/span.cons/assert.other_span.pass.cpp b/libcxx/test/libcxx/containers/views/views.span/span.cons/assert.other_span.pass.cpp
index f1b7d2183625b5..c288c2acd6b59f 100644
--- a/libcxx/test/libcxx/containers/views/views.span/span.cons/assert.other_span.pass.cpp
+++ b/libcxx/test/libcxx/containers/views/views.span/span.cons/assert.other_span.pass.cpp
@@ -15,7 +15,7 @@
// REQUIRES: has-unix-headers
// UNSUPPORTED: libcpp-hardening-mode=none
-// XFAIL: availability-verbose_abort-missing
+// XFAIL: libcpp-hardening-mode=debug && availability-verbose_abort-missing
#include <array>
#include <span>
diff --git a/libcxx/test/libcxx/containers/views/views.span/span.cons/assert.range.pass.cpp b/libcxx/test/libcxx/containers/views/views.span/span.cons/assert.range.pass.cpp
index 18ed7ce213b90a..1f9af3e03009ab 100644
--- a/libcxx/test/libcxx/containers/views/views.span/span.cons/assert.range.pass.cpp
+++ b/libcxx/test/libcxx/containers/views/views.span/span.cons/assert.range.pass.cpp
@@ -15,7 +15,7 @@
// REQUIRES: has-unix-headers
// UNSUPPORTED: libcpp-hardening-mode=none
-// XFAIL: availability-verbose_abort-missing
+// XFAIL: libcpp-hardening-mode=debug && availability-verbose_abort-missing
#include <span>
#include <vector>
diff --git a/libcxx/test/libcxx/containers/views/views.span/span.elem/assert.back.pass.cpp b/libcxx/test/libcxx/containers/views/views.span/span.elem/assert.back.pass.cpp
index d15b024149775e..ea98fe81ee2f8a 100644
--- a/libcxx/test/libcxx/containers/views/views.span/span.elem/assert.back.pass.cpp
+++ b/libcxx/test/libcxx/containers/views/views.span/span.elem/assert.back.pass.cpp
@@ -15,7 +15,7 @@
// REQUIRES: has-unix-headers
// UNSUPPORTED: libcpp-hardening-mode=none
-// XFAIL: availability-verbose_abort-missing
+// XFAIL: libcpp-hardening-mode=debug && availability-verbose_abort-missing
#include <array>
#include <span>
diff --git a/libcxx/test/libcxx/containers/views/views.span/span.elem/assert.front.pass.cpp b/libcxx/test/libcxx/containers/views/views.span/span.elem/assert.front.pass.cpp
index 588123af6499b0..2660ca1f90c141 100644
--- a/libcxx/test/libcxx/containers/views/views.span/span.elem/assert.front.pass.cpp
+++ b/libcxx/test/libcxx/containers/views/views.span/span.elem/assert.front.pass.cpp
@@ -15,7 +15,7 @@
// REQUIRES: has-unix-headers
// UNSUPPORTED: libcpp-hardening-mode=none
-// XFAIL: availability-verbose_abort-missing
+// XFAIL: libcpp-hardening-mode=debug && availability-verbose_abort-missing
#include <array>
#include <span>
diff --git a/libcxx/test/libcxx/containers/views/views.span/span.elem/assert.op_idx.pass.cpp b/libcxx/test/libcxx/containers/views/views.span/span.elem/assert.op_idx.pass.cpp
index 8a74739c79ddfb..e7d79588441818 100644
--- a/libcxx/test/libcxx/containers/views/views.span/span.elem/assert.op_idx.pass.cpp
+++ b/libcxx/test/libcxx/containers/views/views.span/span.elem/assert.op_idx.pass.cpp
@@ -15,7 +15,7 @@
// REQUIRES: has-unix-headers
// UNSUPPORTED: libcpp-hardening-mode=none
-// XFAIL: availability-verbose_abort-missing
+// XFAIL: libcpp-hardening-mode=debug && availability-verbose_abort-missing
#include <array>
#include <span>
diff --git a/libcxx/test/libcxx/containers/views/views.span/span.sub/assert.first.pass.cpp b/libcxx/test/libcxx/containers/views/views.span/span.sub/assert.first.pass.cpp
index 01d5658291f1d9..eb6b442d648499 100644
--- a/libcxx/test/libcxx/containers/views/views.span/span.sub/assert.first.pass.cpp
+++ b/libcxx/test/libcxx/containers/views/views.span/span.sub/assert.first.pass.cpp
@@ -15,7 +15,7 @@
// REQUIRES: has-unix-headers
// UNSUPPORTED: libcpp-hardening-mode=none
-// XFAIL: availability-verbose_abort-missing
+// XFAIL: libcpp-hardening-mode=debug && availability-verbose_abort-missing
#include <array>
#include <span>
diff --git a/libcxx/test/libcxx/containers/views/views.span/span.sub/assert.last.pass.cpp b/libcxx/test/libcxx/containers/views/views.span/span.sub/assert.last.pass.cpp
index 4e6587443c6a78..141735db02a602 100644
--- a/libcxx/test/libcxx/containers/views/views.span/span.sub/assert.last.pass.cpp
+++ b/libcxx/test/libcxx/containers/views/views.span/span.sub/assert.last.pass.cpp
@@ -15,7 +15,7 @@
// REQUIRES: has-unix-headers
// UNSUPPORTED: libcpp-hardening-mode=none
-// XFAIL: availability-verbose_abort-missing
+// XFAIL: libcpp-hardening-mode=debug && availability-verbose_abort-missing
#include <array>
#include <span>
diff --git a/libcxx/test/libcxx/containers/views/views.span/span.sub/assert.subspan.pass.cpp b/libcxx/test/libcxx/containers/views/views.span/span.sub/assert.subspan.pass.cpp
index 52e4fe9ecc5c70..7ed228e96a4837 100644
--- a/libcxx/test/libcxx/containers/views/views.span/span.sub/assert.subspan.pass.cpp
+++ b/libcxx/test/libcxx/containers/views/views.span/span.sub/assert.subspan.pass.cpp
@@ -23,7 +23,7 @@
// REQUIRES: has-unix-headers
// UNSUPPORTED: libcpp-hardening-mode=none
-// XFAIL: availability-verbose_abort-missing
+// XFAIL: libcpp-hardening-mode=debug && availability-verbose_abort-missing
#include <array>
#include <span>
diff --git a/libcxx/test/libcxx/input.output/filesystems/class.path/path.itr/assert.iterator.pass.cpp b/libcxx/test/libcxx/input.output/filesystems/class.path/path.itr/assert.iterator.pass.cpp
index 6c138752b50542..38047957de8e5e 100644
--- a/libcxx/test/libcxx/input.output/filesystems/class.path/path.itr/assert.iterator.pass.cpp
+++ b/libcxx/test/libcxx/input.output/filesystems/class.path/path.itr/assert.iterator.pass.cpp
@@ -9,7 +9,7 @@
// REQUIRES: has-unix-headers
// UNSUPPORTED: c++03
// UNSUPPORTED: !libcpp-hardening-mode=debug
-// XFAIL: availability-verbose_abort-missing
+// XFAIL: libcpp-hardening-mode=debug && availability-verbose_abort-missing
// <filesystem>
diff --git a/libcxx/test/libcxx/iterators/assert.advance.pass.cpp b/libcxx/test/libcxx/iterators/assert.advance.pass.cpp
index b7e6962b443efb..e9d2f27008260a 100644
--- a/libcxx/test/libcxx/iterators/assert.advance.pass.cpp
+++ b/libcxx/test/libcxx/iterators/assert.advance.pass.cpp
@@ -9,7 +9,7 @@
// REQUIRES: has-unix-headers
// UNSUPPORTED: c++03
// REQUIRES: libcpp-hardening-mode={{extensive|debug}}
-// XFAIL: availability-verbose_abort-missing
+// XFAIL: libcpp-hardening-mode=debug && availability-verbose_abort-missing
// <list>
diff --git a/libcxx/test/libcxx/iterators/assert.next.pass.cpp b/libcxx/test/libcxx/iterators/assert.next.pass.cpp
index da4f4ea3150c39..242a0c6f0f7ce4 100644
--- a/libcxx/test/libcxx/iterators/assert.next.pass.cpp
+++ b/libcxx/test/libcxx/iterators/assert.next.pass.cpp
@@ -9,7 +9,7 @@
// REQUIRES: has-unix-headers
// UNSUPPORTED: c++03
// REQUIRES: libcpp-hardening-mode={{extensive|debug}}
-// XFAIL: availability-verbose_abort-missing
+// XFAIL: libcpp-hardening-mode=debug && availability-verbose_abort-missing
// <list>
diff --git a/libcxx/test/libcxx/iterators/assert.prev.pass.cpp b/libcxx/test/libcxx/iterators/assert.prev.pass.cpp
index 6a71cad9ef0489..a5a04f1bbeb6be 100644
--- a/libcxx/test/libcxx/iterators/assert.prev.pass.cpp
+++ b/libcxx/test/libcxx/iterators/assert.prev.pass.cpp
@@ -9,7 +9,7 @@
// REQUIRES: has-unix-headers
// UNSUPPORTED: c++03
// REQUIRES: libcpp-hardening-mode={{extensive|debug}}
-// XFAIL: availability-verbose_abort-missing
+// XFAIL: libcpp-hardening-mode=debug && availability-verbose_abort-missing
// <list>
diff --git a/libcxx/test/libcxx/iterators/bounded_iter/dereference.pass.cpp b/libcxx/test/libcxx/iterators/bounded_iter/dereference.pass.cpp
index 095e8a8fef6ef6..8eee4ad2f319a2 100644
--- a/libcxx/test/libcxx/iterators/bounded_iter/dereference.pass.cpp
+++ b/libcxx/test/libcxx/iterators/bounded_iter/dereference.pass.cpp
@@ -14,7 +14,7 @@
// REQUIRES: has-unix-headers
// UNSUPPORTED: c++03
// UNSUPPORTED: libcpp-hardening-mode=none
-// XFAIL: availability-verbose_abort-missing
+// XFAIL: libcpp-hardening-mode=debug && availability-verbose_abort-missing
#include <iterator>
diff --git a/libcxx/test/libcxx/iterators/predef.iterators/counted.iterator/assert.pass.cpp b/libcxx/test/libcxx/iterators/predef.iterators/counted.iterator/assert.pass.cpp
index f803b2cad75be9..2fafe4727185da 100644
--- a/libcxx/test/libcxx/iterators/predef.iterators/counted.iterator/assert.pass.cpp
+++ b/libcxx/test/libcxx/iterators/predef.iterators/counted.iterator/assert.pass.cpp
@@ -9,7 +9,7 @@
// REQUIRES: has-unix-headers
// UNSUPPORTED: c++03, c++11, c++14, c++17
// UNSUPPORTED: libcpp-hardening-mode=none
-// XFAIL: availability-verbose_abort-missing
+// XFAIL: libcpp-hardening-mode=debug && availability-verbose_abort-missing
#include <iterator>
diff --git a/libcxx/test/libcxx/iterators/predef.iterators/iterators.common/assert.pass.cpp b/libcxx/test/libcxx/iterators/predef.iterators/iterators.common/assert.pass.cpp
index ea4574fc1a9ccf..01c0fb40483207 100644
--- a/libcxx/test/libcxx/iterators/predef.iterators/iterators.common/assert.pass.cpp
+++ b/libcxx/test/libcxx/iterators/predef.iterators/iterators.common/assert.pass.cpp
@@ -9,7 +9,7 @@
// REQUIRES: has-unix-headers
// UNSUPPORTED: c++03, c++11, c++14, c++17
// UNSUPPORTED: libcpp-hardening-mode=none
-// XFAIL: availability-verbose_abort-missing
+// XFAIL: libcpp-hardening-mode=debug && availability-verbose_abort-missing
#include <iterator>
diff --git a/libcxx/test/libcxx/ranges/range.adaptors/range.chunk.by/assert.begin.pass.cpp b/libcxx/test/libcxx/ranges/range.adaptors/range.chunk.by/assert.begin.pass.cpp
index 0ba4745be08267..57af3663170916 100644
--- a/libcxx/test/libcxx/ranges/range.adaptors/range.chunk.by/assert.begin.pass.cpp
+++ b/libcxx/test/libcxx/ranges/range.adaptors/range.chunk.by/assert.begin.pass.cpp
@@ -10,7 +10,7 @@
// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
// UNSUPPORTED: no-exceptions
// UNSUPPORTED: !libcpp-hardening-mode=debug
-// XFAIL: availability-verbose_abort-missing
+// XFAIL: libcpp-hardening-mode=debug && availability-verbose_abort-missing
// <ranges>
diff --git a/libcxx/test/libcxx/ranges/range.adaptors/range.chunk.by/assert.find-next.pass.cpp b/libcxx/test/libcxx/ranges/range.adaptors/range.chunk.by/assert.find-next.pass.cpp
index 9e5536bf51be2b..1c91ee71989529 100644
--- a/libcxx/test/libcxx/ranges/range.adaptors/range.chunk.by/assert.find-next.pass.cpp
+++ b/libcxx/test/libcxx/ranges/range.adaptors/range.chunk.by/assert.find-next.pass.cpp
@@ -10,7 +10,7 @@
// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
// UNSUPPORTED: no-exceptions
// UNSUPPORTED: !libcpp-hardening-mode=debug
-// XFAIL: availability-verbose_abort-missing
+// XFAIL: libcpp-hardening-mode=debug && availability-verbose_abort-missing
// <ranges>
diff --git a/libcxx/test/libcxx/ranges/range.adaptors/range.chunk.by/assert.find-prev.pass.cpp b/libcxx/test/libcxx/ranges/range.adaptors/range.chunk.by/assert.find-prev.pass.cpp
index 4f746cfec2f1a4..2605bf6dde0743 100644
--- a/libcxx/test/libcxx/ranges/range.adaptors/range.chunk.by/assert.find-prev.pass.cpp
+++ b/libcxx/test/libcxx/ranges/range.adaptors/range.chunk.by/assert.find-prev.pass.cpp
@@ -10,7 +10,7 @@
// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
// UNSUPPORTED: no-exceptions
// UNSUPPORTED: !libcpp-hardening-mode=debug
-// XFAIL: availability-verbose_abort-missing
+// XFAIL: libcpp-hardening-mode=debug && availability-verbose_abort-missing
// <ranges>
diff --git a/libcxx/test/libcxx/ranges/range.adaptors/range.chunk.by/range.chunk.by.iter/assert.deref.pass.cpp b/libcxx/test/libcxx/ranges/range.adaptors/range.chunk.by/range.chunk.by.iter/assert.deref.pass.cpp
index 80c08efc56c05e..8ed84ca8b56a16 100644
--- a/libcxx/test/libcxx/ranges/range.adaptors/range.chunk.by/range.chunk.by.iter/assert.deref.pass.cpp
+++ b/libcxx/test/libcxx/ranges/range.adaptors/range.chunk.by/range.chunk.by.iter/assert.deref.pass.cpp
@@ -9,7 +9,7 @@
// REQUIRES: has-unix-headers
// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
// UNSUPPORTED: !libcpp-hardening-mode=debug
-// XFAIL: availability-verbose_abort-missing
+// XFAIL: libcpp-hardening-mode=debug && availability-verbose_abort-missing
// <ranges>
diff --git a/libcxx/test/libcxx/ranges/range.adaptors/range.chunk.by/range.chunk.by.iter/assert.increment.pass.cpp b/libcxx/test/libcxx/ranges/range.adaptors/range.chunk.by/range.chunk.by.iter/assert.increment.pass.cpp
index 7381ad28862939..1a804b71b5e5e5 100644
--- a/libcxx/test/libcxx/ranges/range.adaptors/range.chunk.by/range.chunk.by.iter/assert.increment.pass.cpp
+++ b/libcxx/test/libcxx/ranges/range.adaptors/range.chunk.by/range.chunk.by.iter/assert.increment.pass.cpp
@@ -9,7 +9,7 @@
// REQUIRES: has-unix-headers
// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
// UNSUPPORTED: !libcpp-hardening-mode=debug
-// XFAIL: availability-verbose_abort-missing
+// XFAIL: libcpp-hardening-mode=debug && availability-verbose_abort-missing
// <ranges>
diff --git a/libcxx/test/libcxx/ranges/range.adaptors/range.drop.while/assert.begin.pass.cpp b/libcxx/test/libcxx/ranges/range.adaptors/range.drop.while/assert.begin.pass.cpp
index a2b11fb54ed9da..205cf40746207e 100644
--- a/libcxx/test/libcxx/ranges/range.adaptors/range.drop.while/assert.begin.pass.cpp
+++ b/libcxx/test/libcxx/ranges/range.adaptors/range.drop.while/assert.begin.pass.cpp
@@ -14,7 +14,7 @@
// UNSUPPORTED: c++03, c++11, c++14, c++17
// UNSUPPORTED: no-exceptions
// REQUIRES: libcpp-hardening-mode={{extensive|debug}}
-// XFAIL: availability-verbose_abort-missing
+// XFAIL: libcpp-hardening-mode=debug && availability-verbose_abort-missing
#include <ranges>
diff --git a/libcxx/test/libcxx/ranges/range.adaptors/range.lazy.split/range.lazy.split.inner/assert.equal.pass.cpp b/libcxx/test/libcxx/ranges/range.adaptors/range.lazy.split/range.lazy.split.inner/assert.equal.pass.cpp
index 86ee2841f249e9..22ede4143ffa47 100644
--- a/libcxx/test/libcxx/ranges/range.adaptors/range.lazy.split/range.lazy.split.inner/assert.equal.pass.cpp
+++ b/libcxx/test/libcxx/ranges/range.adaptors/range.lazy.split/range.lazy.split.inner/assert.equal.pass.cpp
@@ -9,7 +9,7 @@
// REQUIRES: has-unix-headers
// UNSUPPORTED: c++03, c++11, c++14, c++17
// REQUIRES: libcpp-hardening-mode={{extensive|debug}}
-// XFAIL: availability-verbose_abort-missing
+// XFAIL: libcpp-hardening-mode=debug && availability-verbose_abort-missing
// <ranges>
diff --git a/libcxx/test/libcxx/ranges/range.adaptors/range.lazy.split/range.lazy.split.outer/assert.equal.pass.cpp b/libcxx/test/libcxx/ranges/range.adaptors/range.lazy.split/range.lazy.split.outer/assert.equal.pass.cpp
index d4a3bbc513c49a..b6cbf5241f744d 100644
--- a/libcxx/test/libcxx/ranges/range.adaptors/range.lazy.split/range.lazy.split.outer/assert.equal.pass.cpp
+++ b/libcxx/test/libcxx/ranges/range.adaptors/range.lazy.split/range.lazy.split.outer/assert.equal.pass.cpp
@@ -9,7 +9,7 @@
// REQUIRES: has-unix-headers
// UNSUPPORTED: c++03, c++11, c++14, c++17
// REQUIRES: libcpp-hardening-mode={{extensive|debug}}
-// XFAIL: availability-verbose_abort-missing
+// XFAIL: libcpp-hardening-mode=debug && availability-verbose_abort-missing
// <ranges>
diff --git a/libcxx/test/libcxx/strings/basic.string/string.access/assert.back.pass.cpp b/libcxx/test/libcxx/strings/basic.string/string.access/assert.back.pass.cpp
index 42beb28c47b136..36a485a1e4d00e 100644
--- a/libcxx/test/libcxx/strings/basic.string/string.access/assert.back.pass.cpp
+++ b/libcxx/test/libcxx/strings/basic.string/string.access/assert.back.pass.cpp
@@ -13,7 +13,7 @@
// REQUIRES: has-unix-headers
// UNSUPPORTED: c++03
// UNSUPPORTED: libcpp-hardening-mode=none
-// XFAIL: availability-verbose_abort-missing
+// XFAIL: libcpp-hardening-mode=debug && availability-verbose_abort-missing
#include <string>
diff --git a/libcxx/test/libcxx/strings/basic.string/string.access/assert.cback.pass.cpp b/libcxx/test/libcxx/strings/basic.string/string.access/assert.cback.pass.cpp
index 7a3d3e1661636a..d810acd67e7e70 100644
--- a/libcxx/test/libcxx/strings/basic.string/string.access/assert.cback.pass.cpp
+++ b/libcxx/test/libcxx/strings/basic.string/string.access/assert.cback.pass.cpp
@@ -13,7 +13,7 @@
// REQUIRES: has-unix-headers
// UNSUPPORTED: c++03
// UNSUPPORTED: libcpp-hardening-mode=none
-// XFAIL: availability-verbose_abort-missing
+// XFAIL: libcpp-hardening-mode=debug && availability-verbose_abort-missing
#include <string>
diff --git a/libcxx/test/libcxx/strings/basic.string/string.access/assert.cfront.pass.cpp b/libcxx/test/libcxx/strings/basic.string/string.access/assert.cfront.pass.cpp
index 66432dc099b5ff..12e7ef3328b04b 100644
--- a/libcxx/test/libcxx/strings/basic.string/string.access/assert.cfront.pass.cpp
+++ b/libcxx/test/libcxx/strings/basic.string/string.access/assert.cfront.pass.cpp
@@ -13,7 +13,7 @@
// REQUIRES: has-unix-headers
// UNSUPPORTED: c++03
// UNSUPPORTED: libcpp-hardening-mode=none
-// XFAIL: availability-verbose_abort-missing
+// XFAIL: libcpp-hardening-mode=debug && availability-verbose_abort-missing
#include <string>
diff --git a/libcxx/test/libcxx/strings/basic.string/string.access/assert.cindex.pass.cpp b/libcxx/test/libcxx/strings/basic.string/string.access/assert.cindex.pass.cpp
index 41bb48b6f574c8..3983352712963f 100644
--- a/libcxx/test/libcxx/strings/basic.string/string.access/assert.cindex.pass.cpp
+++ b/libcxx/test/libcxx/strings/basic.string/string.access/assert.cindex.pass.cpp
@@ -13,7 +13,7 @@
// REQUIRES: has-unix-headers
// UNSUPPORTED: c++03
// UNSUPPORTED: libcpp-hardening-mode=none
-// XFAIL: availability-verbose_abort-missing
+// XFAIL: libcpp-hardening-mode=debug && availability-verbose_abort-missing
#include <string>
#include <cassert>
diff --git a/libcxx/test/libcxx/strings/basic.string/string.access/assert.front.pass.cpp b/libcxx/test/libcxx/strings/basic.string/string.access/assert.front.pass.cpp
index 1033e17961b242..24df3fcad0c5ce 100644
--- a/libcxx/test/libcxx/strings/basic.string/string.access/assert.front.pass.cpp
+++ b/libcxx/test/libcxx/strings/basic.string/string.access/assert.front.pass.cpp
@@ -13,7 +13,7 @@
// REQUIRES: has-unix-headers
// UNSUPPORTED: c++03
// UNSUPPORTED: libcpp-hardening-mode=none
-// XFAIL: availability-verbose_abort-missing
+// XFAIL: libcpp-hardening-mode=debug && availability-verbose_abort-missing
#include <string>
#include <cassert>
diff --git a/libcxx/test/libcxx/strings/basic.string/string.access/assert.index.pass.cpp b/libcxx/test/libcxx/strings/basic.string/string.access/assert.index.pass.cpp
index 776bba32da184d..d26997d8d24c29 100644
--- a/libcxx/test/libcxx/strings/basic.string/string.access/assert.index.pass.cpp
+++ b/libcxx/test/libcxx/strings/basic.string/string.access/assert.index.pass.cpp
@@ -13,7 +13,7 @@
// REQUIRES: has-unix-headers
// UNSUPPORTED: c++03
// UNSUPPORTED: libcpp-hardening-mode=none
-// XFAIL: availability-verbose_abort-missing
+// XFAIL: libcpp-hardening-mode=debug && availability-verbose_abort-missing
#include <string>
#include <cassert>
diff --git a/libcxx/test/libcxx/strings/basic.string/string.modifiers/assert.erase_iter.null.pass.cpp b/libcxx/test/libcxx/strings/basic.string/string.modifiers/assert.erase_iter.null.pass.cpp
index 0b4cb9db51c94c..036e75965c4882 100644
--- a/libcxx/test/libcxx/strings/basic.string/string.modifiers/assert.erase_iter.null.pass.cpp
+++ b/libcxx/test/libcxx/strings/basic.string/string.modifiers/assert.erase_iter.null.pass.cpp
@@ -13,7 +13,7 @@
// REQUIRES: has-unix-headers
// UNSUPPORTED: c++03
// UNSUPPORTED: libcpp-hardening-mode=none
-// XFAIL: availability-verbose_abort-missing
+// XFAIL: libcpp-hardening-mode=debug && availability-verbose_abort-missing
#include <string>
diff --git a/libcxx/test/libcxx/strings/basic.string/string.modifiers/assert.pop_back.pass.cpp b/libcxx/test/libcxx/strings/basic.string/string.modifiers/assert.pop_back.pass.cpp
index 2bab67bdc3edc5..54c011c4d54a0d 100644
--- a/libcxx/test/libcxx/strings/basic.string/string.modifiers/assert.pop_back.pass.cpp
+++ b/libcxx/test/libcxx/strings/basic.string/string.modifiers/assert.pop_back.pass.cpp
@@ -13,7 +13,7 @@
// REQUIRES: has-unix-headers
// UNSUPPORTED: c++03
// UNSUPPORTED: libcpp-hardening-mode=none
-// XFAIL: availability-verbose_abort-missing
+// XFAIL: libcpp-hardening-mode=debug && availability-verbose_abort-missing
#include <string>
diff --git a/libcxx/test/libcxx/strings/string.view/assert.ctor.length.pass.cpp b/libcxx/test/libcxx/strings/string.view/assert.ctor.length.pass.cpp
index addcae5ec1863e..af8b393f9e0a74 100644
--- a/libcxx/test/libcxx/strings/string.view/assert.ctor.length.pass.cpp
+++ b/libcxx/test/libcxx/strings/string.view/assert.ctor.length.pass.cpp
@@ -9,7 +9,7 @@
// REQUIRES: has-unix-headers
// UNSUPPORTED: c++03, c++11
// REQUIRES: libcpp-hardening-mode={{extensive|debug}}
-// XFAIL: availability-verbose_abort-missing
+// XFAIL: libcpp-hardening-mode=debug && availability-verbose_abort-missing
// Construct a string_view from an invalid length
// constexpr basic_string_view( const _CharT* s, size_type len )
diff --git a/libcxx/test/libcxx/strings/string.view/assert.ctor.pointer.pass.cpp b/libcxx/test/libcxx/strings/string.view/assert.ctor.pointer.pass.cpp
index b38e0585d03120..1810ec1ca8ac90 100644
--- a/libcxx/test/libcxx/strings/string.view/assert.ctor.pointer.pass.cpp
+++ b/libcxx/test/libcxx/strings/string.view/assert.ctor.pointer.pass.cpp
@@ -9,7 +9,7 @@
// REQUIRES: has-unix-headers
// UNSUPPORTED: c++03, c++11, c++14
// REQUIRES: libcpp-hardening-mode={{extensive|debug}}
-// XFAIL: availability-verbose_abort-missing
+// XFAIL: libcpp-hardening-mode=debug && availability-verbose_abort-missing
// Construct a string_view from a null pointer
// constexpr basic_string_view( const CharT* s );
diff --git a/libcxx/test/libcxx/thread/futures/futures.promise/assert.set_exception.pass.cpp b/libcxx/test/libcxx/thread/futures/futures.promise/assert.set_exception.pass.cpp
index fe7b3616b5a764..6d5eb5ef9931f5 100644
--- a/libcxx/test/libcxx/thread/futures/futures.promise/assert.set_exception.pass.cpp
+++ b/libcxx/test/libcxx/thread/futures/futures.promise/assert.set_exception.pass.cpp
@@ -9,7 +9,7 @@
// REQUIRES: has-unix-headers
// UNSUPPORTED: c++03, no-threads
// REQUIRES: libcpp-hardening-mode={{extensive|debug}}
-// XFAIL: availability-verbose_abort-missing
+// XFAIL: libcpp-hardening-mode=debug && availability-verbose_abort-missing
// <future>
diff --git a/libcxx/test/libcxx/thread/futures/futures.promise/assert.set_exception_at_thread_exit.pass.cpp b/libcxx/test/libcxx/thread/futures/futures.promise/assert.set_exception_at_thread_exit.pass.cpp
index f28db8caba9497..1bffde5e3ebd1f 100644
--- a/libcxx/test/libcxx/thread/futures/futures.promise/assert.set_exception_at_thread_exit.pass.cpp
+++ b/libcxx/test/libcxx/thread/futures/futures.promise/assert.set_exception_at_thread_exit.pass.cpp
@@ -9,7 +9,7 @@
// REQUIRES: has-unix-headers
// UNSUPPORTED: c++03, no-threads
// REQUIRES: libcpp-hardening-mode={{extensive|debug}}
-// XFAIL: availability-verbose_abort-missing
+// XFAIL: libcpp-hardening-mode=debug && availability-verbose_abort-missing
// <future>
diff --git a/libcxx/test/libcxx/thread/thread.barrier/assert.arrive.pass.cpp b/libcxx/test/libcxx/thread/thread.barrier/assert.arrive.pass.cpp
index 58bc4b844eb59d..419a603a037f80 100644
--- a/libcxx/test/libcxx/thread/thread.barrier/assert.arrive.pass.cpp
+++ b/libcxx/test/libcxx/thread/thread.barrier/assert.arrive.pass.cpp
@@ -9,7 +9,7 @@
// UNSUPPORTED: c++03, c++11, c++14, c++17
// REQUIRES: libcpp-hardening-mode={{extensive|debug}}
-// XFAIL: availability-verbose_abort-missing
+// XFAIL: libcpp-hardening-mode=debug && availability-verbose_abort-missing
// REQUIRES: has-unix-headers
diff --git a/libcxx/test/libcxx/thread/thread.barrier/assert.ctor.pass.cpp b/libcxx/test/libcxx/thread/thread.barrier/assert.ctor.pass.cpp
index 3af43bdbe7b139..0b4fb1d675eaa7 100644
--- a/libcxx/test/libcxx/thread/thread.barrier/assert.ctor.pass.cpp
+++ b/libcxx/test/libcxx/thread/thread.barrier/assert.ctor.pass.cpp
@@ -9,7 +9,7 @@
// UNSUPPORTED: c++03, c++11, c++14, c++17
// REQUIRES: libcpp-hardening-mode={{extensive|debug}}
-// XFAIL: availability-verbose_abort-missing
+// XFAIL: libcpp-hardening-mode=debug && availability-verbose_abort-missing
// REQUIRES: has-unix-headers
diff --git a/libcxx/test/libcxx/thread/thread.latch/assert.arrive_and_wait.pass.cpp b/libcxx/test/libcxx/thread/thread.latch/assert.arrive_and_wait.pass.cpp
index 442ae0d962631a..e61679554a62e1 100644
--- a/libcxx/test/libcxx/thread/thread.latch/assert.arrive_and_wait.pass.cpp
+++ b/libcxx/test/libcxx/thread/thread.latch/assert.arrive_and_wait.pass.cpp
@@ -18,7 +18,7 @@
// REQUIRES: has-unix-headers
// REQUIRES: libcpp-hardening-mode={{extensive|debug}}
-// XFAIL: availability-verbose_abort-missing
+// XFAIL: libcpp-hardening-mode=debug && availability-verbose_abort-missing
#include <latch>
diff --git a/libcxx/test/libcxx/thread/thread.latch/assert.count_down.pass.cpp b/libcxx/test/libcxx/thread/thread.latch/assert.count_down.pass.cpp
index 1547dd6390d6cb..6220cba02af195 100644
--- a/libcxx/test/libcxx/thread/thread.latch/assert.count_down.pass.cpp
+++ b/libcxx/test/libcxx/thread/thread.latch/assert.count_down.pass.cpp
@@ -19,7 +19,7 @@
// REQUIRES: has-unix-headers
// REQUIRES: libcpp-hardening-mode={{extensive|debug}}
-// XFAIL: availability-verbose_abort-missing
+// XFAIL: libcpp-hardening-mode=debug && availability-verbose_abort-missing
#include <latch>
diff --git a/libcxx/test/libcxx/thread/thread.latch/assert.ctor.pass.cpp b/libcxx/test/libcxx/thread/thread.latch/assert.ctor.pass.cpp
index b20911e0c3b9f0..5f1ea19d82a503 100644
--- a/libcxx/test/libcxx/thread/thread.latch/assert.ctor.pass.cpp
+++ b/libcxx/test/libcxx/thread/thread.latch/assert.ctor.pass.cpp
@@ -18,7 +18,7 @@
// REQUIRES: has-unix-headers
// REQUIRES: libcpp-hardening-mode={{extensive|debug}}
-// XFAIL: availability-verbose_abort-missing
+// XFAIL: libcpp-hardening-mode=debug && availability-verbose_abort-missing
#include <latch>
diff --git a/libcxx/test/libcxx/thread/thread.semaphore/assert.ctor.pass.cpp b/libcxx/test/libcxx/thread/thread.semaphore/assert.ctor.pass.cpp
index 91b1e354290888..1e33add7794968 100644
--- a/libcxx/test/libcxx/thread/thread.semaphore/assert.ctor.pass.cpp
+++ b/libcxx/test/libcxx/thread/thread.semaphore/assert.ctor.pass.cpp
@@ -9,7 +9,7 @@
// UNSUPPORTED: c++03, c++11, c++14, c++17
// REQUIRES: libcpp-hardening-mode={{extensive|debug}}
-// XFAIL: availability-verbose_abort-missing
+// XFAIL: libcpp-hardening-mode=debug && availability-verbose_abort-missing
// REQUIRES: has-unix-headers
diff --git a/libcxx/test/libcxx/thread/thread.semaphore/assert.release.pass.cpp b/libcxx/test/libcxx/thread/thread.semaphore/assert.release.pass.cpp
index 09b4de36653597..a5a01a38478784 100644
--- a/libcxx/test/libcxx/thread/thread.semaphore/assert.release.pass.cpp
+++ b/libcxx/test/libcxx/thread/thread.semaphore/assert.release.pass.cpp
@@ -9,7 +9,7 @@
// UNSUPPORTED: c++03, c++11, c++14, c++17
// REQUIRES: libcpp-hardening-mode={{extensive|debug}}
-// XFAIL: availability-verbose_abort-missing
+// XFAIL: libcpp-hardening-mode=debug && availability-verbose_abort-missing
// REQUIRES: has-unix-headers
diff --git a/libcxx/test/libcxx/utilities/assert.exception_guard.no_exceptions.pass.cpp b/libcxx/test/libcxx/utilities/assert.exception_guard.no_exceptions.pass.cpp
index cf6b7bef3ebcec..c6ddb8bd252a40 100644
--- a/libcxx/test/libcxx/utilities/assert.exception_guard.no_exceptions.pass.cpp
+++ b/libcxx/test/libcxx/utilities/assert.exception_guard.no_exceptions.pass.cpp
@@ -9,7 +9,7 @@
// REQUIRES: has-unix-headers
// UNSUPPORTED: c++03
// REQUIRES: libcpp-hardening-mode=debug
-// XFAIL: availability-verbose_abort-missing
+// XFAIL: libcpp-hardening-mode=debug && availability-verbose_abort-missing
// ADDITIONAL_COMPILE_FLAGS: -fno-exceptions
#include <__utility/exception_guard.h>
diff --git a/libcxx/test/libcxx/utilities/expected/expected.expected/assert.arrow.pass.cpp b/libcxx/test/libcxx/utilities/expected/expected.expected/assert.arrow.pass.cpp
index 27dcdfe951230a..47481bcbef8a8a 100644
--- a/libcxx/test/libcxx/utilities/expected/expected.expected/assert.arrow.pass.cpp
+++ b/libcxx/test/libcxx/utilities/expected/expected.expected/assert.arrow.pass.cpp
@@ -9,7 +9,7 @@
// REQUIRES: has-unix-headers
// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
// UNSUPPORTED: libcpp-hardening-mode=none
-// XFAIL: availability-verbose_abort-missing
+// XFAIL: libcpp-hardening-mode=debug && availability-verbose_abort-missing
// constexpr const T* operator->() const noexcept;
// constexpr T* operator->() noexcept;
diff --git a/libcxx/test/libcxx/utilities/expected/expected.expected/assert.deref.pass.cpp b/libcxx/test/libcxx/utilities/expected/expected.expected/assert.deref.pass.cpp
index 01078ac27e96a9..5ab43d38ccb15b 100644
--- a/libcxx/test/libcxx/utilities/expected/expected.expected/assert.deref.pass.cpp
+++ b/libcxx/test/libcxx/utilities/expected/expected.expected/assert.deref.pass.cpp
@@ -9,7 +9,7 @@
// REQUIRES: has-unix-headers
// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
// UNSUPPORTED: libcpp-hardening-mode=none
-// XFAIL: availability-verbose_abort-missing
+// XFAIL: libcpp-hardening-mode=debug && availability-verbose_abort-missing
// constexpr const T& operator*() const & noexcept;
// constexpr T& operator*() & noexcept;
diff --git a/libcxx/test/libcxx/utilities/expected/expected.expected/assert.error.pass.cpp b/libcxx/test/libcxx/utilities/expected/expected.expected/assert.error.pass.cpp
index ff574b350cc9e1..92bf305994c183 100644
--- a/libcxx/test/libcxx/utilities/expected/expected.expected/assert.error.pass.cpp
+++ b/libcxx/test/libcxx/utilities/expected/expected.expected/assert.error.pass.cpp
@@ -9,7 +9,7 @@
// REQUIRES: has-unix-headers
// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
// UNSUPPORTED: libcpp-hardening-mode=none
-// XFAIL: availability-verbose_abort-missing
+// XFAIL: libcpp-hardening-mode=debug && availability-verbose_abort-missing
// constexpr const E& error() const & noexcept;
// constexpr E& error() & noexcept;
diff --git a/libcxx/test/libcxx/utilities/expected/expected.void/assert.deref.pass.cpp b/libcxx/test/libcxx/utilities/expected/expected.void/assert.deref.pass.cpp
index e5d7ac3eae6988..6f1ba075b3245f 100644
--- a/libcxx/test/libcxx/utilities/expected/expected.void/assert.deref.pass.cpp
+++ b/libcxx/test/libcxx/utilities/expected/expected.void/assert.deref.pass.cpp
@@ -9,7 +9,7 @@
// REQUIRES: has-unix-headers
// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
// UNSUPPORTED: libcpp-hardening-mode=none
-// XFAIL: availability-verbose_abort-missing
+// XFAIL: libcpp-hardening-mode=debug && availability-verbose_abort-missing
// constexpr void operator*() const noexcept;
//
diff --git a/libcxx/test/libcxx/utilities/expected/expected.void/assert.error.pass.cpp b/libcxx/test/libcxx/utilities/expected/expected.void/assert.error.pass.cpp
index 7bf4844b29b017..a1c92ff85f33a2 100644
--- a/libcxx/test/libcxx/utilities/expected/expected.void/assert.error.pass.cpp
+++ b/libcxx/test/libcxx/utilities/expected/expected.void/assert.error.pass.cpp
@@ -9,7 +9,7 @@
// REQUIRES: has-unix-headers
// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
// UNSUPPORTED: libcpp-hardening-mode=none
-// XFAIL: availability-verbose_abort-missing
+// XFAIL: libcpp-hardening-mode=debug && availability-verbose_abort-missing
// constexpr const E& error() const & noexcept;
// constexpr E& error() & noexcept;
diff --git a/libcxx/test/libcxx/utilities/optional/optional.object/optional.object.observe/assert.dereference.pass.cpp b/libcxx/test/libcxx/utilities/optional/optional.object/optional.object.observe/assert.dereference.pass.cpp
index 2ba5f299bc34e6..31938b3f8fbaa1 100644
--- a/libcxx/test/libcxx/utilities/optional/optional.object/optional.object.observe/assert.dereference.pass.cpp
+++ b/libcxx/test/libcxx/utilities/optional/optional.object/optional.object.observe/assert.dereference.pass.cpp
@@ -16,7 +16,7 @@
// REQUIRES: has-unix-headers
// UNSUPPORTED: c++03, c++11, c++14
// UNSUPPORTED: libcpp-hardening-mode=none
-// XFAIL: availability-verbose_abort-missing
+// XFAIL: libcpp-hardening-mode=debug && availability-verbose_abort-missing
#include <optional>
diff --git a/libcxx/test/libcxx/utilities/optional/optional.object/optional.object.observe/assert.op_arrow.pass.cpp b/libcxx/test/libcxx/utilities/optional/optional.object/optional.object.observe/assert.op_arrow.pass.cpp
index f93569979d1886..52009628327db6 100644
--- a/libcxx/test/libcxx/utilities/optional/optional.object/optional.object.observe/assert.op_arrow.pass.cpp
+++ b/libcxx/test/libcxx/utilities/optional/optional.object/optional.object.observe/assert.op_arrow.pass.cpp
@@ -14,7 +14,7 @@
// REQUIRES: has-unix-headers
// UNSUPPORTED: c++03, c++11, c++14
// UNSUPPORTED: libcpp-hardening-mode=none
-// XFAIL: availability-verbose_abort-missing
+// XFAIL: libcpp-hardening-mode=debug && availability-verbose_abort-missing
#include <optional>
More information about the libcxx-commits
mailing list