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 <cassert> 13 #include <cstdarg> 14 #include <cstddef> 15 #include <cstdio> 16 #include <cstdlib> 17 #include <exception> 18 #include <regex> 19 #include <string> 20 #include <string_view> 21 #include <utility> 22 23 #include <unistd.h> 24 #include <errno.h> 25 #include <sys/wait.h> 26 #include "test_macros.h" 27 #include "test_allocator.h" 28 29 #if TEST_STD_VER < 11 30 # error "C++11 or greater is required to use this header" 31 #endif 32 33 struct AssertionInfoMatcher { 34 static const int any_line = -1; 35 static constexpr const char* any_file = "*"; 36 static constexpr const char* any_msg = "*"; 37 38 constexpr AssertionInfoMatcher() : is_empty_(true), msg_(any_msg, __builtin_strlen(any_msg)), file_(any_file, __builtin_strlen(any_file)), line_(any_line) { } 39 constexpr AssertionInfoMatcher(const char* msg, const char* file = any_file, int line = any_line) 40 : is_empty_(false), msg_(msg, __builtin_strlen(msg)), file_(file, __builtin_strlen(file)), line_(line) {} 41 42 bool Matches(char const* file, int line, char const* message) const { 43 assert(!empty() && "empty matcher"); 44 45 if (CheckLineMatches(line) && CheckFileMatches(file) && CheckMessageMatches(message)) 46 return true; 47 // Write to stdout because that's the file descriptor captured by the parent 48 // process. 49 std::printf("Failed to match assertion info!\n%s\nVS\n%s:%d (%s)\n", ToString().data(), file, line, message); 50 return false; 51 } 52 53 std::string ToString() const { 54 std::string result = "msg = \""; result += msg_; result += "\"\n"; 55 result += "line = " + (line_ == any_line ? "'*'" : std::to_string(line_)) + "\n"; 56 result += "file = " + (file_ == any_file ? "'*'" : std::string(file_)); 57 return result; 58 } 59 60 bool empty() const { return is_empty_; } 61 private: 62 bool CheckLineMatches(int got_line) const { 63 if (line_ == any_line) 64 return true; 65 return got_line == line_; 66 } 67 68 bool CheckFileMatches(std::string_view got_file) const { 69 assert(!empty() && "empty matcher"); 70 if (file_ == any_file) 71 return true; 72 std::size_t found_at = got_file.find(file_); 73 if (found_at == std::string_view::npos) 74 return false; 75 // require the match start at the beginning of the file or immediately after 76 // a directory separator. 77 if (found_at != 0) { 78 char last_char = got_file[found_at - 1]; 79 if (last_char != '/' && last_char != '\\') 80 return false; 81 } 82 // require the match goes until the end of the string. 83 return got_file.substr(found_at) == file_; 84 } 85 86 bool CheckMessageMatches(std::string_view got_msg) const { 87 assert(!empty() && "empty matcher"); 88 if (msg_ == any_msg) 89 return true; 90 std::size_t found_at = got_msg.find(msg_); 91 if (found_at == std::string_view::npos) 92 return false; 93 return found_at == 0 && got_msg.size() == msg_.size(); 94 } 95 private: 96 bool is_empty_; 97 std::string_view msg_; 98 std::string_view file_; 99 int line_; 100 }; 101 102 static constexpr AssertionInfoMatcher AnyMatcher(AssertionInfoMatcher::any_msg); 103 104 inline AssertionInfoMatcher& GlobalMatcher() { 105 static AssertionInfoMatcher GMatch; 106 return GMatch; 107 } 108 109 struct DeathTest { 110 enum ResultKind { 111 RK_DidNotDie, RK_MatchFound, RK_MatchFailure, RK_Terminate, RK_SetupFailure, RK_Unknown 112 }; 113 114 static const char* ResultKindToString(ResultKind RK) { 115 #define CASE(K) case K: return #K 116 switch (RK) { 117 CASE(RK_MatchFailure); 118 CASE(RK_DidNotDie); 119 CASE(RK_SetupFailure); 120 CASE(RK_MatchFound); 121 CASE(RK_Unknown); 122 CASE(RK_Terminate); 123 } 124 return "not a result kind"; 125 } 126 127 static bool IsValidResultKind(int val) { 128 return val >= RK_DidNotDie && val <= RK_Unknown; 129 } 130 131 DeathTest(AssertionInfoMatcher const& Matcher) : matcher_(Matcher) {} 132 133 template <class Func> 134 ResultKind Run(Func&& f) { 135 int pipe_res = pipe(stdout_pipe_fd_); 136 assert(pipe_res != -1 && "failed to create pipe"); 137 pipe_res = pipe(stderr_pipe_fd_); 138 assert(pipe_res != -1 && "failed to create pipe"); 139 pid_t child_pid = fork(); 140 assert(child_pid != -1 && 141 "failed to fork a process to perform a death test"); 142 child_pid_ = child_pid; 143 if (child_pid_ == 0) { 144 RunForChild(std::forward<Func>(f)); 145 assert(false && "unreachable"); 146 } 147 return RunForParent(); 148 } 149 150 int getChildExitCode() const { return exit_code_; } 151 std::string const& getChildStdOut() const { return stdout_from_child_; } 152 std::string const& getChildStdErr() const { return stderr_from_child_; } 153 private: 154 template <class Func> 155 TEST_NORETURN void RunForChild(Func&& f) { 156 close(GetStdOutReadFD()); // don't need to read from the pipe in the child. 157 close(GetStdErrReadFD()); 158 auto DupFD = [](int DestFD, int TargetFD) { 159 int dup_result = dup2(DestFD, TargetFD); 160 if (dup_result == -1) 161 std::exit(RK_SetupFailure); 162 }; 163 DupFD(GetStdOutWriteFD(), STDOUT_FILENO); 164 DupFD(GetStdErrWriteFD(), STDERR_FILENO); 165 166 GlobalMatcher() = matcher_; 167 f(); 168 std::exit(RK_DidNotDie); 169 } 170 171 static std::string ReadChildIOUntilEnd(int FD) { 172 std::string error_msg; 173 char buffer[256]; 174 int num_read; 175 do { 176 while ((num_read = read(FD, buffer, 255)) > 0) { 177 buffer[num_read] = '\0'; 178 error_msg += buffer; 179 } 180 } while (num_read == -1 && errno == EINTR); 181 return error_msg; 182 } 183 184 void CaptureIOFromChild() { 185 close(GetStdOutWriteFD()); // no need to write from the parent process 186 close(GetStdErrWriteFD()); 187 stdout_from_child_ = ReadChildIOUntilEnd(GetStdOutReadFD()); 188 stderr_from_child_ = ReadChildIOUntilEnd(GetStdErrReadFD()); 189 close(GetStdOutReadFD()); 190 close(GetStdErrReadFD()); 191 } 192 193 ResultKind RunForParent() { 194 CaptureIOFromChild(); 195 196 int status_value; 197 pid_t result = waitpid(child_pid_, &status_value, 0); 198 assert(result != -1 && "there is no child process to wait for"); 199 200 if (WIFEXITED(status_value)) { 201 exit_code_ = WEXITSTATUS(status_value); 202 if (!IsValidResultKind(exit_code_)) 203 return RK_Unknown; 204 return static_cast<ResultKind>(exit_code_); 205 } 206 return RK_Unknown; 207 } 208 209 DeathTest(DeathTest const&) = delete; 210 DeathTest& operator=(DeathTest const&) = delete; 211 212 int GetStdOutReadFD() const { 213 return stdout_pipe_fd_[0]; 214 } 215 216 int GetStdOutWriteFD() const { 217 return stdout_pipe_fd_[1]; 218 } 219 220 int GetStdErrReadFD() const { 221 return stderr_pipe_fd_[0]; 222 } 223 224 int GetStdErrWriteFD() const { 225 return stderr_pipe_fd_[1]; 226 } 227 private: 228 AssertionInfoMatcher matcher_; 229 pid_t child_pid_ = -1; 230 int exit_code_ = -1; 231 int stdout_pipe_fd_[2]; 232 int stderr_pipe_fd_[2]; 233 std::string stdout_from_child_; 234 std::string stderr_from_child_; 235 }; 236 237 #ifdef _LIBCPP_VERSION 238 void std::__libcpp_verbose_abort(char const* printf_format, ...) { 239 // Extract information from the error message. This has to stay synchronized with how we format assertions in the 240 // library. 241 va_list args; 242 va_start(args, printf_format); 243 char const* message = va_arg(args, char const*); 244 245 std::regex message_format("(.*):(\\d+): assertion (.*) failed: (.*)\\n"); 246 247 std::cmatch match_result; 248 bool has_match = std::regex_match(message, match_result, message_format); 249 assert(has_match); 250 assert(match_result.size() == 5); 251 252 std::string file = match_result[1]; 253 int line = std::stoi(match_result[2]); 254 // Omitting `expression` in `match_result[3]` 255 std::string failure_reason = match_result[4]; 256 257 if (GlobalMatcher().Matches(file.c_str(), line, failure_reason.c_str())) { 258 std::exit(DeathTest::RK_MatchFound); 259 } 260 std::exit(DeathTest::RK_MatchFailure); 261 } 262 #endif // _LIBCPP_VERSION 263 264 [[noreturn]] inline void terminate_handler() { 265 std::exit(DeathTest::RK_Terminate); 266 } 267 268 template <class Func> 269 inline bool ExpectDeath(const char* stmt, Func&& func, AssertionInfoMatcher Matcher) { 270 std::set_terminate(terminate_handler); 271 DeathTest DT(Matcher); 272 DeathTest::ResultKind RK = DT.Run(func); 273 auto OnFailure = [&](const char* msg) { 274 std::fprintf(stderr, "EXPECT_DEATH( %s ) failed! (%s)\n\n", stmt, msg); 275 if (RK != DeathTest::RK_Unknown) { 276 std::fprintf(stderr, "child exit code: %d\n", DT.getChildExitCode()); 277 } 278 if (!DT.getChildStdErr().empty()) { 279 std::fprintf(stderr, "---------- standard err ----------\n%s\n", DT.getChildStdErr().c_str()); 280 } 281 if (!DT.getChildStdOut().empty()) { 282 std::fprintf(stderr, "---------- standard out ----------\n%s\n", DT.getChildStdOut().c_str()); 283 } 284 return false; 285 }; 286 switch (RK) { 287 case DeathTest::RK_MatchFound: 288 case DeathTest::RK_Terminate: 289 return true; 290 case DeathTest::RK_SetupFailure: 291 return OnFailure("child failed to setup test environment"); 292 case DeathTest::RK_Unknown: 293 return OnFailure("reason unknown"); 294 case DeathTest::RK_DidNotDie: 295 return OnFailure("child did not die"); 296 case DeathTest::RK_MatchFailure: 297 return OnFailure("matcher failed"); 298 } 299 assert(false && "unreachable"); 300 } 301 302 template <class Func> 303 inline bool ExpectDeath(const char* stmt, Func&& func) { 304 return ExpectDeath(stmt, func, AnyMatcher); 305 } 306 307 /// Assert that the specified expression throws a libc++ debug exception. 308 #define EXPECT_DEATH(...) assert((ExpectDeath(#__VA_ARGS__, [&]() { __VA_ARGS__; } ))) 309 310 #define EXPECT_STD_TERMINATE(...) assert(ExpectDeath(#__VA_ARGS__, __VA_ARGS__)) 311 312 #define EXPECT_DEATH_MATCHES(Matcher, ...) assert((ExpectDeath(#__VA_ARGS__, [&]() { __VA_ARGS__; }, Matcher))) 313 314 #define TEST_LIBCPP_ASSERT_FAILURE(expr, message) assert((ExpectDeath(#expr, [&]() { (void)(expr); }, AssertionInfoMatcher(message)))) 315 316 #endif // TEST_SUPPORT_CHECK_ASSERTION_H 317