brintos

brintos / llvm-project-archived public Read only

0
0
Text · 17.7 KiB · 8416de7 Raw
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