507 lines · c
1//===----------------------------------------------------------------------===//2//3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.4// See https://llvm.org/LICENSE.txt for license information.5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception6//7//===----------------------------------------------------------------------===//8 9#ifndef TEST_SUPPORT_CHECK_ASSERTION_H10#define TEST_SUPPORT_CHECK_ASSERTION_H11 12#include <array>13#include <cassert>14#include <csignal>15#include <cstdarg>16#include <cstddef>17#include <cstdio>18#include <cstdlib>19#include <exception>20#include <functional>21#include <regex>22#include <sstream>23#include <string>24#include <string_view>25#include <utility>26 27#include <unistd.h>28#include <errno.h>29#include <signal.h>30#include <sys/wait.h>31 32#include "test_macros.h"33#include "test_allocator.h"34 35#if TEST_STD_VER < 1136# error "C++11 or greater is required to use this header"37#endif38 39// When printing the assertion message to `stderr`, delimit it with a marker to make it easier to match the message40// later.41static constexpr const char* Marker = "###";42 43// (success, error-message-if-failed)44using MatchResult = std::pair<bool, std::string>;45using Matcher = std::function<MatchResult(const std::string& /*text*/)>;46 47// Using the marker makes matching more precise, but we cannot output the marker when the `observe` semantic is used48// (because it doesn't allow customizing the logging function). If the marker is not available, fall back to using less49// precise matching by just the error message.50MatchResult MatchAssertionMessage(const std::string& text, std::string_view expected_message, bool use_marker) {51 // Extract information from the error message. This has to stay synchronized with how we format assertions in the52 // library.53 std::string assertion_format_string = [&] {54 if (use_marker)55 return (".*###\\n(.*):(\\d+): libc\\+\\+ Hardening assertion (.*) failed: (.*)\\n###");56 return ("(.*):(\\d+): libc\\+\\+ Hardening assertion (.*) failed: (.*)\\n");57 }();58 std::regex assertion_format(assertion_format_string);59 60 std::smatch match_result;61 // If a non-terminating assertion semantic is used, more than one assertion might be triggered before the process62 // dies, so we cannot expect the entire target string to match.63 bool has_match = std::regex_search(text, match_result, assertion_format);64 if (!has_match || match_result.size() != 5) {65 std::stringstream matching_error;66 matching_error //67 << "Failed to parse the assertion message.\n" //68 << "Using marker: " << use_marker << "\n" //69 << "Expected message: '" << expected_message.data() << "'\n" //70 << "Stderr contents: '" << text.c_str() << "'\n";71 return MatchResult(/*success=*/false, matching_error.str());72 }73 74 const std::string& file = match_result[1];75 int line = std::stoi(match_result[2]);76 // Omitting `expression` in `match_result[3]`77 const std::string& assertion_message = match_result[4];78 79 bool result = assertion_message == expected_message;80 if (!result) {81 std::stringstream matching_error;82 matching_error //83 << "Expected message: '" << expected_message.data() << "'\n" //84 << "Actual message: '" << assertion_message.c_str() << "'\n" //85 << "Source location: " << file << ":" << std::to_string(line) << "\n";86 return MatchResult(/*success=*/false, matching_error.str());87 }88 89 return MatchResult(/*success=*/true, /*maybe_error=*/"");90}91 92Matcher MakeAssertionMessageMatcher(std::string_view assertion_message, bool use_marker = true) {93 return [=](const std::string& text) { //94 return MatchAssertionMessage(text, assertion_message, use_marker);95 };96}97 98Matcher MakeAnyMatcher() {99 return [](const std::string&) { //100 return MatchResult(/*success=*/true, /*maybe_error=*/"");101 };102}103 104enum class DeathCause {105 // Valid causes.106 VerboseAbort = 1,107 StdAbort,108 StdTerminate,109 Trap,110 // Causes that might be invalid or might stem from undefined behavior (relevant for non-terminating assertion111 // semantics).112 DidNotDie,113 Segfault,114 ArithmeticError,115 // Always invalid causes.116 SetupFailure,117 Unknown118};119 120bool IsValidCause(DeathCause cause) {121 switch (cause) {122 case DeathCause::VerboseAbort:123 case DeathCause::StdAbort:124 case DeathCause::StdTerminate:125 case DeathCause::Trap:126 return true;127 default:128 return false;129 }130}131 132bool IsTestSetupErrorCause(DeathCause cause) {133 switch (cause) {134 case DeathCause::SetupFailure:135 case DeathCause::Unknown:136 return true;137 default:138 return false;139 }140}141 142std::string ToString(DeathCause cause) {143 switch (cause) {144 case DeathCause::VerboseAbort:145 return "verbose abort";146 case DeathCause::StdAbort:147 return "`std::abort`";148 case DeathCause::StdTerminate:149 return "`std::terminate`";150 case DeathCause::Trap:151 return "trap";152 case DeathCause::DidNotDie:153 return "<invalid cause (child did not die)>";154 case DeathCause::Segfault:155 return "<invalid cause (segmentation fault)>";156 case DeathCause::ArithmeticError:157 return "<invalid cause (fatal arithmetic error)>";158 case DeathCause::SetupFailure:159 return "<test setup error (child failed to set up test environment)>";160 case DeathCause::Unknown:161 return "<test setup error (test doesn't know how to interpret the death cause)>";162 }163 164 assert(false && "Unreachable");165}166 167template <std::size_t N>168std::string ToString(std::array<DeathCause, N> const& causes) {169 std::stringstream ss;170 ss << "{";171 for (std::size_t i = 0; i != N; ++i) {172 ss << ToString(causes[i]);173 if (i + 1 != N)174 ss << ", ";175 }176 ss << "}";177 return ss.str();178}179 180[[noreturn]] void StopChildProcess(DeathCause cause) { std::exit(static_cast<int>(cause)); }181 182DeathCause ConvertToDeathCause(int val) {183 if (val < static_cast<int>(DeathCause::VerboseAbort) || val > static_cast<int>(DeathCause::Unknown)) {184 return DeathCause::Unknown;185 }186 return static_cast<DeathCause>(val);187}188 189enum class Outcome {190 Success,191 UnexpectedCause,192 UnexpectedErrorMessage,193 InvalidCause,194};195 196std::string ToString(Outcome outcome) {197 switch (outcome) {198 case Outcome::Success:199 return "success";200 case Outcome::UnexpectedCause:201 return "unexpected death cause";202 case Outcome::UnexpectedErrorMessage:203 return "unexpected error message";204 case Outcome::InvalidCause:205 return "invalid death cause";206 }207 208 assert(false && "Unreachable");209}210 211class DeathTestResult {212public:213 DeathTestResult() = default;214 DeathTestResult(Outcome set_outcome, DeathCause set_cause, const std::string& set_failure_description = "")215 : outcome_(set_outcome), cause_(set_cause), failure_description_(set_failure_description) {}216 217 bool success() const { return outcome() == Outcome::Success; }218 Outcome outcome() const { return outcome_; }219 DeathCause cause() const { return cause_; }220 const std::string& failure_description() const { return failure_description_; }221 222private:223 Outcome outcome_ = Outcome::Success;224 DeathCause cause_ = DeathCause::Unknown;225 std::string failure_description_;226};227 228class DeathTest {229public:230 DeathTest() = default;231 DeathTest(DeathTest const&) = delete;232 DeathTest& operator=(DeathTest const&) = delete;233 234 template <std::size_t N, class Func>235 DeathTestResult Run(const std::array<DeathCause, N>& expected_causes, Func&& func, const Matcher& matcher) {236 std::signal(SIGABRT, [](int) { StopChildProcess(DeathCause::StdAbort); });237 std::set_terminate([] { StopChildProcess(DeathCause::StdTerminate); });238 239 DeathCause cause = Run(func);240 241 if (!IsValidCause(cause)) {242 return DeathTestResult(Outcome::InvalidCause, cause, ToString(cause));243 }244 245 if (std::find(expected_causes.begin(), expected_causes.end(), cause) == expected_causes.end()) {246 std::stringstream failure_description;247 failure_description //248 << "Child died, but with a different death cause\n" //249 << "Expected cause(s): " << ToString(expected_causes) << "\n" //250 << "Actual cause: " << ToString(cause) << "\n";251 return DeathTestResult(Outcome::UnexpectedCause, cause, failure_description.str());252 }253 254 MatchResult match_result = matcher(GetChildStdErr());255 if (!match_result.first) {256 auto failure_description = std::string("Child died, but with a different error message\n") + match_result.second;257 return DeathTestResult(Outcome::UnexpectedErrorMessage, cause, failure_description);258 }259 260 return DeathTestResult(Outcome::Success, cause);261 }262 263 // When non-terminating assertion semantics are used, the program will invoke UB which might or might not crash the264 // process; we make sure that the execution produces the expected error message but otherwise consider the test run265 // successful whether the child process dies or not.266 template <class Func>267 DeathTestResult RunWithoutGuaranteedDeath(Func&& func, const Matcher& matcher) {268 std::signal(SIGABRT, [](int) { StopChildProcess(DeathCause::StdAbort); });269 std::set_terminate([] { StopChildProcess(DeathCause::StdTerminate); });270 271 DeathCause cause = Run(func);272 273 if (IsTestSetupErrorCause(cause)) {274 return DeathTestResult(Outcome::InvalidCause, cause, ToString(cause));275 }276 277 MatchResult match_result = matcher(GetChildStdErr());278 if (!match_result.first) {279 auto failure_description = std::string("Child produced a different error message\n") + match_result.second;280 return DeathTestResult(Outcome::UnexpectedErrorMessage, cause, failure_description);281 }282 283 return DeathTestResult(Outcome::Success, cause);284 }285 286 void PrintFailureDetails(std::string_view invocation,287 std::string_view failure_description,288 std::string_view stmt,289 DeathCause cause) const {290 std::fprintf(stderr,291 "Failure: %s( %s ) failed!\n(reason: %s)\n\n",292 invocation.data(),293 stmt.data(),294 failure_description.data());295 296 if (cause != DeathCause::Unknown) {297 std::fprintf(stderr, "child exit code: %d\n", GetChildExitCode());298 }299 std::fprintf(stderr, "---------- standard err ----------\n%s", GetChildStdErr().c_str());300 std::fprintf(stderr, "\n----------------------------------\n");301 std::fprintf(stderr, "---------- standard out ----------\n%s", GetChildStdOut().c_str());302 std::fprintf(stderr, "\n----------------------------------\n");303 };304 305private:306 int GetChildExitCode() const { return exit_code_; }307 std::string const& GetChildStdOut() const { return stdout_from_child_; }308 std::string const& GetChildStdErr() const { return stderr_from_child_; }309 310 template <class Func>311 DeathCause Run(Func&& f) {312 int pipe_res = pipe(stdout_pipe_fd_);313 assert(pipe_res != -1 && "failed to create pipe");314 pipe_res = pipe(stderr_pipe_fd_);315 assert(pipe_res != -1 && "failed to create pipe");316 pid_t child_pid = fork();317 assert(child_pid != -1 && "failed to fork a process to perform a death test");318 child_pid_ = child_pid;319 if (child_pid_ == 0) {320 RunForChild(std::forward<Func>(f));321 assert(false && "unreachable");322 }323 return RunForParent();324 }325 326 template <class Func>327 [[noreturn]] void RunForChild(Func&& f) {328 close(GetStdOutReadFD()); // don't need to read from the pipe in the child.329 close(GetStdErrReadFD());330 auto DupFD = [](int DestFD, int TargetFD) {331 int dup_result = dup2(DestFD, TargetFD);332 if (dup_result == -1)333 StopChildProcess(DeathCause::SetupFailure);334 };335 DupFD(GetStdOutWriteFD(), STDOUT_FILENO);336 DupFD(GetStdErrWriteFD(), STDERR_FILENO);337 338 f();339 StopChildProcess(DeathCause::DidNotDie);340 }341 342 static std::string ReadChildIOUntilEnd(int FD) {343 std::string error_msg;344 char buffer[256];345 int num_read;346 do {347 while ((num_read = read(FD, buffer, 255)) > 0) {348 buffer[num_read] = '\0';349 error_msg += buffer;350 }351 } while (num_read == -1 && errno == EINTR);352 return error_msg;353 }354 355 void CaptureIOFromChild() {356 close(GetStdOutWriteFD()); // no need to write from the parent process357 close(GetStdErrWriteFD());358 stdout_from_child_ = ReadChildIOUntilEnd(GetStdOutReadFD());359 stderr_from_child_ = ReadChildIOUntilEnd(GetStdErrReadFD());360 close(GetStdOutReadFD());361 close(GetStdErrReadFD());362 }363 364 DeathCause RunForParent() {365 CaptureIOFromChild();366 367 int status_value;368 pid_t result = waitpid(child_pid_, &status_value, 0);369 assert(result != -1 && "there is no child process to wait for");370 371 if (WIFEXITED(status_value)) {372 exit_code_ = WEXITSTATUS(status_value);373 return ConvertToDeathCause(exit_code_);374 }375 376 if (WIFSIGNALED(status_value)) {377 exit_code_ = WTERMSIG(status_value);378 // `__builtin_trap` generates `SIGILL` on x86 and `SIGTRAP` on ARM.379 if (exit_code_ == SIGILL || exit_code_ == SIGTRAP) {380 return DeathCause::Trap;381 }382 if (exit_code_ == SIGSEGV) {383 return DeathCause::Segfault;384 }385 if (exit_code_ == SIGFPE) {386 return DeathCause::ArithmeticError;387 }388 }389 390 return DeathCause::Unknown;391 }392 393 int GetStdOutReadFD() const { return stdout_pipe_fd_[0]; }394 int GetStdOutWriteFD() const { return stdout_pipe_fd_[1]; }395 int GetStdErrReadFD() const { return stderr_pipe_fd_[0]; }396 int GetStdErrWriteFD() const { return stderr_pipe_fd_[1]; }397 398 pid_t child_pid_ = -1;399 int exit_code_ = -1;400 int stdout_pipe_fd_[2];401 int stderr_pipe_fd_[2];402 std::string stdout_from_child_;403 std::string stderr_from_child_;404};405 406#ifdef _LIBCPP_VERSION407void std::__libcpp_verbose_abort(char const* format, ...) noexcept {408 va_list args;409 va_start(args, format);410 411 std::fprintf(stderr, "%s\n", Marker);412 std::vfprintf(stderr, format, args);413 std::fprintf(stderr, "%s", Marker);414 415 va_end(args);416 417 StopChildProcess(DeathCause::VerboseAbort);418}419#endif // _LIBCPP_VERSION420 421template <std::size_t N, class Func>422bool ExpectDeath(423 const std::array<DeathCause, N>& expected_causes, const char* stmt, Func&& func, const Matcher& matcher) {424 for (auto cause : expected_causes)425 assert(IsValidCause(cause));426 427 DeathTest test_case;428 DeathTestResult test_result = test_case.Run(expected_causes, func, matcher);429 if (!test_result.success()) {430 test_case.PrintFailureDetails("EXPECT_DEATH", test_result.failure_description(), stmt, test_result.cause());431 }432 433 return test_result.success();434}435 436template <class Func>437bool ExpectDeath(DeathCause expected_cause, const char* stmt, Func&& func, const Matcher& matcher) {438 return ExpectDeath(std::array<DeathCause, 1>{expected_cause}, stmt, func, matcher);439}440 441template <std::size_t N, class Func>442bool ExpectDeath(const std::array<DeathCause, N>& expected_causes, const char* stmt, Func&& func) {443 return ExpectDeath(expected_causes, stmt, func, MakeAnyMatcher());444}445 446template <class Func>447bool ExpectDeath(DeathCause expected_cause, const char* stmt, Func&& func) {448 return ExpectDeath(std::array<DeathCause, 1>{expected_cause}, stmt, func, MakeAnyMatcher());449}450 451template <class Func>452bool ExpectLog(const char* stmt, Func&& func, const Matcher& matcher) {453 DeathTest test_case;454 DeathTestResult test_result = test_case.RunWithoutGuaranteedDeath(func, matcher);455 if (!test_result.success()) {456 test_case.PrintFailureDetails("EXPECT_LOG", test_result.failure_description(), stmt, test_result.cause());457 }458 459 return test_result.success();460}461 462template <class Func>463bool ExpectLog(const char* stmt, Func&& func) {464 return ExpectLog(stmt, func, MakeAnyMatcher());465}466 467// clang-format off468 469/// Assert that the specified expression aborts with the expected cause and, optionally, error message.470#define EXPECT_ANY_DEATH(...) \471 assert(( ExpectDeath(std::array<DeathCause, 4>{DeathCause::VerboseAbort, DeathCause::StdAbort, DeathCause::StdTerminate, DeathCause::Trap}, #__VA_ARGS__, [&]() { __VA_ARGS__; } ) ))472#define EXPECT_DEATH(...) \473 assert(( ExpectDeath(DeathCause::VerboseAbort, #__VA_ARGS__, [&]() { __VA_ARGS__; } ) ))474#define EXPECT_DEATH_MATCHES(matcher, ...) \475 assert(( ExpectDeath(DeathCause::VerboseAbort, #__VA_ARGS__, [&]() { __VA_ARGS__; }, matcher) ))476#define EXPECT_STD_ABORT(...) \477 assert( ExpectDeath(DeathCause::StdAbort, #__VA_ARGS__, [&]() { __VA_ARGS__; }) )478#define EXPECT_STD_TERMINATE(...) \479 assert( ExpectDeath(DeathCause::StdTerminate, #__VA_ARGS__, __VA_ARGS__) )480 481#if defined(_LIBCPP_ASSERTION_SEMANTIC)482 483#if _LIBCPP_ASSERTION_SEMANTIC == _LIBCPP_ASSERTION_SEMANTIC_ENFORCE484#define TEST_LIBCPP_ASSERT_FAILURE(expr, message) \485 assert(( ExpectDeath(DeathCause::VerboseAbort, #expr, [&]() { (void)(expr); }, MakeAssertionMessageMatcher(message)) ))486#elif _LIBCPP_ASSERTION_SEMANTIC == _LIBCPP_ASSERTION_SEMANTIC_QUICK_ENFORCE487#define TEST_LIBCPP_ASSERT_FAILURE(expr, message) \488 assert(( ExpectDeath(DeathCause::Trap, #expr, [&]() { (void)(expr); }) ))489#elif _LIBCPP_ASSERTION_SEMANTIC == _LIBCPP_ASSERTION_SEMANTIC_OBSERVE490#define TEST_LIBCPP_ASSERT_FAILURE(expr, message) \491 assert(( ExpectLog(#expr, [&]() { (void)(expr); }, MakeAssertionMessageMatcher(message, /*use_marker=*/false)) ))492#elif _LIBCPP_ASSERTION_SEMANTIC == _LIBCPP_ASSERTION_SEMANTIC_IGNORE493#define TEST_LIBCPP_ASSERT_FAILURE(expr, message) \494 assert(( ExpectLog(#expr, [&]() { (void)(expr); }) ))495#else496#error "Unknown value for _LIBCPP_ASSERTION_SEMANTIC"497#endif // _LIBCPP_ASSERTION_SEMANTIC == _LIBCPP_ASSERTION_SEMANTIC_ENFORCE498 499#else500#define TEST_LIBCPP_ASSERT_FAILURE(expr, message) \501 assert(( ExpectDeath(DeathCause::Trap, #expr, [&]() { (void)(expr); }) ))502#endif // defined(_LIBCPP_ASSERTION_SEMANTIC)503 504// clang-format on505 506#endif // TEST_SUPPORT_CHECK_ASSERTION_H507