[libcxx-commits] [libcxx] DRAFT [libc++][hardening] In production hardening modes, trap rather than abort (PR #78561)
Louis Dionne via libcxx-commits
libcxx-commits at lists.llvm.org
Thu Jan 18 13:05:53 PST 2024
================
@@ -199,118 +360,86 @@ 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_;
std::string stderr_from_child_;
};
#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*);
+ va_start(args, format);
- std::regex message_format("(.*):(\\d+): assertion (.*) failed: (.*)\\n");
+ std::fprintf(stderr, "%s\n", AssertionInfoMatcher::Marker);
+ std::vfprintf(stderr, format, args);
+ std::fprintf(stderr, "%s", AssertionInfoMatcher::Marker);
- std::cmatch match_result;
- bool has_match = std::regex_match(message, match_result, message_format);
- assert(has_match);
- assert(match_result.size() == 5);
+ va_end(args);
- 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];
-
- 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) {
----------------
ldionne wrote:
```suggestion
bool ExpectDeath(DeathCause expected_cause, const char* stmt, Func&& func) {
```
While we're at it?
https://github.com/llvm/llvm-project/pull/78561
More information about the libcxx-commits
mailing list