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-exception 6 // 7 //===----------------------------------------------------------------------===// 8 9 #ifndef TEST_SUPPORT_CHECK_ASSERTION_H 10 #define TEST_SUPPORT_CHECK_ASSERTION_H 11 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 < 11 36 # error "C++11 or greater is required to use this header" 37 #endif 38 39 // When printing the assertion message to `stderr`, delimit it with a marker to make it easier to match the message 40 // later. 41 static constexpr const char* Marker = "###"; 42 43 // (success, error-message-if-failed) 44 using MatchResult = std::pair<bool, std::string>; 45 using Matcher = std::function<MatchResult(const std::string& /*text*/)>; 46 47 MatchResult MatchAssertionMessage(const std::string& text, std::string_view expected_message) { 48 // Extract information from the error message. This has to stay synchronized with how we format assertions in the 49 // library. 50 std::regex assertion_format(".*###\\n(.*):(\\d+): assertion (.*) failed: (.*)\\n###"); 51 52 std::smatch match_result; 53 bool has_match = std::regex_match(text, match_result, assertion_format); 54 assert(has_match); 55 assert(match_result.size() == 5); 56 57 const std::string& file = match_result[1]; 58 int line = std::stoi(match_result[2]); 59 // Omitting `expression` in `match_result[3]` 60 const std::string& assertion_message = match_result[4]; 61 62 bool result = assertion_message == expected_message; 63 if (!result) { 64 std::stringstream matching_error; 65 matching_error // 66 << "Expected message: '" << expected_message.data() << "'\n" // 67 << "Actual message: '" << assertion_message.c_str() << "'\n" // 68 << "Source location: " << file << ":" << std::to_string(line) << "\n"; 69 return MatchResult(/*success=*/false, matching_error.str()); 70 } 71 72 return MatchResult(/*success=*/true, /*maybe_error=*/""); 73 } 74 75 Matcher MakeAssertionMessageMatcher(std::string_view assertion_message) { 76 return [=](const std::string& text) { // 77 return MatchAssertionMessage(text, assertion_message); 78 }; 79 } 80 81 Matcher MakeAnyMatcher() { 82 return [](const std::string&) { // 83 return MatchResult(/*success=*/true, /*maybe_error=*/""); 84 }; 85 } 86 87 enum class DeathCause { 88 // Valid causes 89 VerboseAbort = 1, 90 StdAbort, 91 StdTerminate, 92 Trap, 93 // Invalid causes 94 DidNotDie, 95 SetupFailure, 96 Unknown 97 }; 98 99 bool IsValidCause(DeathCause cause) { 100 switch (cause) { 101 case DeathCause::VerboseAbort: 102 case DeathCause::StdAbort: 103 case DeathCause::StdTerminate: 104 case DeathCause::Trap: 105 return true; 106 default: 107 return false; 108 } 109 } 110 111 std::string ToString(DeathCause cause) { 112 switch (cause) { 113 case DeathCause::VerboseAbort: 114 return "verbose abort"; 115 case DeathCause::StdAbort: 116 return "`std::abort`"; 117 case DeathCause::StdTerminate: 118 return "`std::terminate`"; 119 case DeathCause::Trap: 120 return "trap"; 121 case DeathCause::DidNotDie: 122 return "<invalid cause (child did not die)>"; 123 case DeathCause::SetupFailure: 124 return "<invalid cause (child failed to set up test environment)>"; 125 case DeathCause::Unknown: 126 return "<invalid cause (cause unknown)>"; 127 } 128 129 assert(false && "Unreachable"); 130 } 131 132 template <std::size_t N> 133 std::string ToString(std::array<DeathCause, N> const& causes) { 134 std::stringstream ss; 135 ss << "{"; 136 for (std::size_t i = 0; i != N; ++i) { 137 ss << ToString(causes[i]); 138 if (i + 1 != N) 139 ss << ", "; 140 } 141 ss << "}"; 142 return ss.str(); 143 } 144 145 [[noreturn]] void StopChildProcess(DeathCause cause) { std::exit(static_cast<int>(cause)); } 146 147 DeathCause ConvertToDeathCause(int val) { 148 if (val < static_cast<int>(DeathCause::VerboseAbort) || val > static_cast<int>(DeathCause::Unknown)) { 149 return DeathCause::Unknown; 150 } 151 return static_cast<DeathCause>(val); 152 } 153 154 enum class Outcome { 155 Success, 156 UnexpectedCause, 157 UnexpectedErrorMessage, 158 InvalidCause, 159 }; 160 161 std::string ToString(Outcome outcome) { 162 switch (outcome) { 163 case Outcome::Success: 164 return "success"; 165 case Outcome::UnexpectedCause: 166 return "unexpected death cause"; 167 case Outcome::UnexpectedErrorMessage: 168 return "unexpected error message"; 169 case Outcome::InvalidCause: 170 return "invalid death cause"; 171 } 172 173 assert(false && "Unreachable"); 174 } 175 176 class DeathTestResult { 177 public: 178 DeathTestResult() = default; 179 DeathTestResult(Outcome set_outcome, DeathCause set_cause, const std::string& set_failure_description = "") 180 : outcome_(set_outcome), cause_(set_cause), failure_description_(set_failure_description) {} 181 182 bool success() const { return outcome() == Outcome::Success; } 183 Outcome outcome() const { return outcome_; } 184 DeathCause cause() const { return cause_; } 185 const std::string& failure_description() const { return failure_description_; } 186 187 private: 188 Outcome outcome_ = Outcome::Success; 189 DeathCause cause_ = DeathCause::Unknown; 190 std::string failure_description_; 191 }; 192 193 class DeathTest { 194 public: 195 DeathTest() = default; 196 DeathTest(DeathTest const&) = delete; 197 DeathTest& operator=(DeathTest const&) = delete; 198 199 template <std::size_t N, class Func> 200 DeathTestResult Run(const std::array<DeathCause, N>& expected_causes, Func&& func, const Matcher& matcher) { 201 std::signal(SIGABRT, [](int) { StopChildProcess(DeathCause::StdAbort); }); 202 std::set_terminate([] { StopChildProcess(DeathCause::StdTerminate); }); 203 204 DeathCause cause = Run(func); 205 206 if (!IsValidCause(cause)) { 207 return DeathTestResult(Outcome::InvalidCause, cause, ToString(cause)); 208 } 209 210 if (std::find(expected_causes.begin(), expected_causes.end(), cause) == expected_causes.end()) { 211 std::stringstream failure_description; 212 failure_description // 213 << "Child died, but with a different death cause\n" // 214 << "Expected cause(s): " << ToString(expected_causes) << "\n" // 215 << "Actual cause: " << ToString(cause) << "\n"; 216 return DeathTestResult(Outcome::UnexpectedCause, cause, failure_description.str()); 217 } 218 219 MatchResult match_result = matcher(GetChildStdErr()); 220 if (!match_result.first) { 221 auto failure_description = std::string("Child died, but with a different error message\n") + match_result.second; 222 return DeathTestResult(Outcome::UnexpectedErrorMessage, cause, failure_description); 223 } 224 225 return DeathTestResult(Outcome::Success, cause); 226 } 227 228 void PrintFailureDetails(std::string_view failure_description, std::string_view stmt, DeathCause cause) const { 229 std::fprintf( 230 stderr, "Failure: EXPECT_DEATH( %s ) failed!\n(reason: %s)\n\n", stmt.data(), failure_description.data()); 231 232 if (cause != DeathCause::Unknown) { 233 std::fprintf(stderr, "child exit code: %d\n", GetChildExitCode()); 234 } 235 std::fprintf(stderr, "---------- standard err ----------\n%s", GetChildStdErr().c_str()); 236 std::fprintf(stderr, "\n----------------------------------\n"); 237 std::fprintf(stderr, "---------- standard out ----------\n%s", GetChildStdOut().c_str()); 238 std::fprintf(stderr, "\n----------------------------------\n"); 239 }; 240 241 private: 242 int GetChildExitCode() const { return exit_code_; } 243 std::string const& GetChildStdOut() const { return stdout_from_child_; } 244 std::string const& GetChildStdErr() const { return stderr_from_child_; } 245 246 template <class Func> 247 DeathCause Run(Func&& f) { 248 int pipe_res = pipe(stdout_pipe_fd_); 249 assert(pipe_res != -1 && "failed to create pipe"); 250 pipe_res = pipe(stderr_pipe_fd_); 251 assert(pipe_res != -1 && "failed to create pipe"); 252 pid_t child_pid = fork(); 253 assert(child_pid != -1 && "failed to fork a process to perform a death test"); 254 child_pid_ = child_pid; 255 if (child_pid_ == 0) { 256 RunForChild(std::forward<Func>(f)); 257 assert(false && "unreachable"); 258 } 259 return RunForParent(); 260 } 261 262 template <class Func> 263 [[noreturn]] void RunForChild(Func&& f) { 264 close(GetStdOutReadFD()); // don't need to read from the pipe in the child. 265 close(GetStdErrReadFD()); 266 auto DupFD = [](int DestFD, int TargetFD) { 267 int dup_result = dup2(DestFD, TargetFD); 268 if (dup_result == -1) 269 StopChildProcess(DeathCause::SetupFailure); 270 }; 271 DupFD(GetStdOutWriteFD(), STDOUT_FILENO); 272 DupFD(GetStdErrWriteFD(), STDERR_FILENO); 273 274 f(); 275 StopChildProcess(DeathCause::DidNotDie); 276 } 277 278 static std::string ReadChildIOUntilEnd(int FD) { 279 std::string error_msg; 280 char buffer[256]; 281 int num_read; 282 do { 283 while ((num_read = read(FD, buffer, 255)) > 0) { 284 buffer[num_read] = '\0'; 285 error_msg += buffer; 286 } 287 } while (num_read == -1 && errno == EINTR); 288 return error_msg; 289 } 290 291 void CaptureIOFromChild() { 292 close(GetStdOutWriteFD()); // no need to write from the parent process 293 close(GetStdErrWriteFD()); 294 stdout_from_child_ = ReadChildIOUntilEnd(GetStdOutReadFD()); 295 stderr_from_child_ = ReadChildIOUntilEnd(GetStdErrReadFD()); 296 close(GetStdOutReadFD()); 297 close(GetStdErrReadFD()); 298 } 299 300 DeathCause RunForParent() { 301 CaptureIOFromChild(); 302 303 int status_value; 304 pid_t result = waitpid(child_pid_, &status_value, 0); 305 assert(result != -1 && "there is no child process to wait for"); 306 307 if (WIFEXITED(status_value)) { 308 exit_code_ = WEXITSTATUS(status_value); 309 return ConvertToDeathCause(exit_code_); 310 } 311 312 if (WIFSIGNALED(status_value)) { 313 exit_code_ = WTERMSIG(status_value); 314 // `__builtin_trap` generqtes `SIGILL` on x86 and `SIGTRAP` on ARM. 315 if (exit_code_ == SIGILL || exit_code_ == SIGTRAP) { 316 return DeathCause::Trap; 317 } 318 } 319 320 return DeathCause::Unknown; 321 } 322 323 int GetStdOutReadFD() const { return stdout_pipe_fd_[0]; } 324 int GetStdOutWriteFD() const { return stdout_pipe_fd_[1]; } 325 int GetStdErrReadFD() const { return stderr_pipe_fd_[0]; } 326 int GetStdErrWriteFD() const { return stderr_pipe_fd_[1]; } 327 328 pid_t child_pid_ = -1; 329 int exit_code_ = -1; 330 int stdout_pipe_fd_[2]; 331 int stderr_pipe_fd_[2]; 332 std::string stdout_from_child_; 333 std::string stderr_from_child_; 334 }; 335 336 #ifdef _LIBCPP_VERSION 337 void std::__libcpp_verbose_abort(char const* format, ...) noexcept { 338 va_list args; 339 va_start(args, format); 340 341 std::fprintf(stderr, "%s\n", Marker); 342 std::vfprintf(stderr, format, args); 343 std::fprintf(stderr, "%s", Marker); 344 345 va_end(args); 346 347 StopChildProcess(DeathCause::VerboseAbort); 348 } 349 #endif // _LIBCPP_VERSION 350 351 template <std::size_t N, class Func> 352 bool ExpectDeath( 353 const std::array<DeathCause, N>& expected_causes, const char* stmt, Func&& func, const Matcher& matcher) { 354 for (auto cause : expected_causes) 355 assert(IsValidCause(cause)); 356 357 DeathTest test_case; 358 DeathTestResult test_result = test_case.Run(expected_causes, func, matcher); 359 if (!test_result.success()) { 360 test_case.PrintFailureDetails(test_result.failure_description(), stmt, test_result.cause()); 361 } 362 363 return test_result.success(); 364 } 365 366 template <class Func> 367 bool ExpectDeath(DeathCause expected_cause, const char* stmt, Func&& func, const Matcher& matcher) { 368 return ExpectDeath(std::array<DeathCause, 1>{expected_cause}, stmt, func, matcher); 369 } 370 371 template <std::size_t N, class Func> 372 bool ExpectDeath(const std::array<DeathCause, N>& expected_causes, const char* stmt, Func&& func) { 373 return ExpectDeath(expected_causes, stmt, func, MakeAnyMatcher()); 374 } 375 376 template <class Func> 377 bool ExpectDeath(DeathCause expected_cause, const char* stmt, Func&& func) { 378 return ExpectDeath(std::array<DeathCause, 1>{expected_cause}, stmt, func, MakeAnyMatcher()); 379 } 380 381 // clang-format off 382 383 /// Assert that the specified expression aborts with the expected cause and, optionally, error message. 384 #define EXPECT_ANY_DEATH(...) \ 385 assert(( ExpectDeath(std::array<DeathCause, 4>{DeathCause::VerboseAbort, DeathCause::StdAbort, DeathCause::StdTerminate, DeathCause::Trap}, #__VA_ARGS__, [&]() { __VA_ARGS__; } ) )) 386 #define EXPECT_DEATH(...) \ 387 assert(( ExpectDeath(DeathCause::VerboseAbort, #__VA_ARGS__, [&]() { __VA_ARGS__; } ) )) 388 #define EXPECT_DEATH_MATCHES(matcher, ...) \ 389 assert(( ExpectDeath(DeathCause::VerboseAbort, #__VA_ARGS__, [&]() { __VA_ARGS__; }, matcher) )) 390 #define EXPECT_STD_ABORT(...) \ 391 assert( ExpectDeath(DeathCause::StdAbort, #__VA_ARGS__, [&]() { __VA_ARGS__; }) ) 392 #define EXPECT_STD_TERMINATE(...) \ 393 assert( ExpectDeath(DeathCause::StdTerminate, #__VA_ARGS__, __VA_ARGS__) ) 394 395 #if defined(_LIBCPP_HARDENING_MODE) && _LIBCPP_HARDENING_MODE == _LIBCPP_HARDENING_MODE_DEBUG 396 #define TEST_LIBCPP_ASSERT_FAILURE(expr, message) \ 397 assert(( ExpectDeath(DeathCause::VerboseAbort, #expr, [&]() { (void)(expr); }, MakeAssertionMessageMatcher(message)) )) 398 #else 399 #define TEST_LIBCPP_ASSERT_FAILURE(expr, message) \ 400 assert(( ExpectDeath(DeathCause::Trap, #expr, [&]() { (void)(expr); }) )) 401 #endif // _LIBCPP_HARDENING_MODE == _LIBCPP_HARDENING_MODE_DEBUG 402 403 // clang-format on 404 405 #endif // TEST_SUPPORT_CHECK_ASSERTION_H 406