[PowerPC][NFC] Cleanup PPCCTRLoopsVerify pass
[llvm-project.git] / libcxx / test / support / debug_mode_helper.h
blobfdda3d77e5055c14a4cd3612f2fae2a796952c31
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 //===----------------------------------------------------------------------===//
9 #ifndef TEST_SUPPORT_DEBUG_MODE_HELPER_H
10 #define TEST_SUPPORT_DEBUG_MODE_HELPER_H
12 #ifndef _LIBCPP_DEBUG
13 #error _LIBCPP_DEBUG must be defined before including this header
14 #endif
16 #include <ciso646>
17 #ifndef _LIBCPP_VERSION
18 #error "This header may only be used for libc++ tests"
19 #endif
21 #include <__debug>
22 #include <cassert>
23 #include <cstddef>
24 #include <cstdio>
25 #include <cstdlib>
26 #include <string>
27 #include <string_view>
28 #include <utility>
30 #include <unistd.h>
31 #include <errno.h>
32 #include <sys/wait.h>
33 #include "test_macros.h"
34 #include "test_allocator.h"
36 #if TEST_STD_VER < 11
37 # error "C++11 or greater is required to use this header"
38 #endif
40 struct DebugInfoMatcher {
41 static const int any_line = -1;
42 static constexpr const char* any_file = "*";
43 static constexpr const char* any_msg = "*";
45 constexpr DebugInfoMatcher() : is_empty(true), msg(any_msg, __builtin_strlen(any_msg)), file(any_file, __builtin_strlen(any_file)), line(any_line) { }
46 constexpr DebugInfoMatcher(const char* msg_, const char* file_ = any_file, int line_ = any_line)
47 : is_empty(false), msg(msg_, __builtin_strlen(msg_)), file(file_, __builtin_strlen(file_)), line(line_) {}
49 bool Matches(std::__libcpp_debug_info const& got) const {
50 assert(!empty() && "empty matcher");
52 if (CheckLineMatches(got.__line_) && CheckFileMatches(got.__file_) &&
53 CheckMessageMatches(got.__msg_))
54 return true;
55 // Write to stdout because that's the file descriptor captured by the parent
56 // process.
57 std::printf("Failed to match debug info!\n%s\nVS\n%s\n", ToString().data(), got.what().data());
58 return false;
61 std::string ToString() const {
62 std::string result = "msg = \""; result += msg; result += "\"\n";
63 result += "line = " + (line == any_line ? "'*'" : std::to_string(line)) + "\n";
64 result += "file = " + (file == any_file ? "'*'" : std::string(any_file));
65 return result;
68 bool empty() const { return is_empty; }
69 private:
70 bool CheckLineMatches(int got_line) const {
71 if (line == any_line)
72 return true;
73 return got_line == line;
76 bool CheckFileMatches(std::string_view got_file) const {
77 assert(!empty() && "empty matcher");
78 if (file == any_file)
79 return true;
80 std::size_t found_at = got_file.find(file);
81 if (found_at == std::string_view::npos)
82 return false;
83 // require the match start at the beginning of the file or immediately after
84 // a directory separator.
85 if (found_at != 0) {
86 char last_char = got_file[found_at - 1];
87 if (last_char != '/' && last_char != '\\')
88 return false;
90 // require the match goes until the end of the string.
91 return got_file.substr(found_at) == file;
94 bool CheckMessageMatches(std::string_view got_msg) const {
95 assert(!empty() && "empty matcher");
96 if (msg == any_msg)
97 return true;
98 std::size_t found_at = got_msg.find(msg);
99 if (found_at == std::string_view::npos)
100 return false;
101 // Allow any match
102 return true;
104 private:
105 bool is_empty;
106 std::string_view msg;
107 std::string_view file;
108 int line;
111 static constexpr DebugInfoMatcher AnyMatcher(DebugInfoMatcher::any_msg);
113 inline DebugInfoMatcher& GlobalMatcher() {
114 static DebugInfoMatcher GMatch;
115 return GMatch;
118 struct DeathTest {
119 enum ResultKind {
120 RK_DidNotDie, RK_MatchFound, RK_MatchFailure, RK_SetupFailure, RK_Unknown
123 static const char* ResultKindToString(ResultKind RK) {
124 #define CASE(K) case K: return #K
125 switch (RK) {
126 CASE(RK_MatchFailure);
127 CASE(RK_DidNotDie);
128 CASE(RK_SetupFailure);
129 CASE(RK_MatchFound);
130 CASE(RK_Unknown);
132 return "not a result kind";
135 static bool IsValidResultKind(int val) {
136 return val >= RK_DidNotDie && val <= RK_Unknown;
139 TEST_NORETURN static void DeathTestDebugHandler(std::__libcpp_debug_info const& info) {
140 assert(!GlobalMatcher().empty());
141 if (GlobalMatcher().Matches(info)) {
142 std::exit(RK_MatchFound);
144 std::exit(RK_MatchFailure);
148 DeathTest(DebugInfoMatcher const& Matcher) : matcher_(Matcher) {}
150 template <class Func>
151 ResultKind Run(Func&& f) {
152 int pipe_res = pipe(stdout_pipe_fd_);
153 assert(pipe_res != -1 && "failed to create pipe");
154 pipe_res = pipe(stderr_pipe_fd_);
155 assert(pipe_res != -1 && "failed to create pipe");
156 pid_t child_pid = fork();
157 assert(child_pid != -1 &&
158 "failed to fork a process to perform a death test");
159 child_pid_ = child_pid;
160 if (child_pid_ == 0) {
161 RunForChild(std::forward<Func>(f));
162 assert(false && "unreachable");
164 return RunForParent();
167 int getChildExitCode() const { return exit_code_; }
168 std::string const& getChildStdOut() const { return stdout_from_child_; }
169 std::string const& getChildStdErr() const { return stderr_from_child_; }
170 private:
171 template <class Func>
172 TEST_NORETURN void RunForChild(Func&& f) {
173 close(GetStdOutReadFD()); // don't need to read from the pipe in the child.
174 close(GetStdErrReadFD());
175 auto DupFD = [](int DestFD, int TargetFD) {
176 int dup_result = dup2(DestFD, TargetFD);
177 if (dup_result == -1)
178 std::exit(RK_SetupFailure);
180 DupFD(GetStdOutWriteFD(), STDOUT_FILENO);
181 DupFD(GetStdErrWriteFD(), STDERR_FILENO);
183 GlobalMatcher() = matcher_;
184 std::__libcpp_set_debug_function(&DeathTestDebugHandler);
185 f();
186 std::exit(RK_DidNotDie);
189 static std::string ReadChildIOUntilEnd(int FD) {
190 std::string error_msg;
191 char buffer[256];
192 int num_read;
193 do {
194 while ((num_read = read(FD, buffer, 255)) > 0) {
195 buffer[num_read] = '\0';
196 error_msg += buffer;
198 } while (num_read == -1 && errno == EINTR);
199 return error_msg;
202 void CaptureIOFromChild() {
203 close(GetStdOutWriteFD()); // no need to write from the parent process
204 close(GetStdErrWriteFD());
205 stdout_from_child_ = ReadChildIOUntilEnd(GetStdOutReadFD());
206 stderr_from_child_ = ReadChildIOUntilEnd(GetStdErrReadFD());
207 close(GetStdOutReadFD());
208 close(GetStdErrReadFD());
211 ResultKind RunForParent() {
212 CaptureIOFromChild();
214 int status_value;
215 pid_t result = waitpid(child_pid_, &status_value, 0);
216 assert(result != -1 && "there is no child process to wait for");
218 if (WIFEXITED(status_value)) {
219 exit_code_ = WEXITSTATUS(status_value);
220 if (!IsValidResultKind(exit_code_))
221 return RK_Unknown;
222 return static_cast<ResultKind>(exit_code_);
224 return RK_Unknown;
227 DeathTest(DeathTest const&) = delete;
228 DeathTest& operator=(DeathTest const&) = delete;
230 int GetStdOutReadFD() const {
231 return stdout_pipe_fd_[0];
234 int GetStdOutWriteFD() const {
235 return stdout_pipe_fd_[1];
238 int GetStdErrReadFD() const {
239 return stderr_pipe_fd_[0];
242 int GetStdErrWriteFD() const {
243 return stderr_pipe_fd_[1];
245 private:
246 DebugInfoMatcher matcher_;
247 pid_t child_pid_ = -1;
248 int exit_code_ = -1;
249 int stdout_pipe_fd_[2];
250 int stderr_pipe_fd_[2];
251 std::string stdout_from_child_;
252 std::string stderr_from_child_;
255 template <class Func>
256 inline bool ExpectDeath(const char* stmt, Func&& func, DebugInfoMatcher Matcher) {
257 DeathTest DT(Matcher);
258 DeathTest::ResultKind RK = DT.Run(func);
259 auto OnFailure = [&](const char* msg) {
260 std::fprintf(stderr, "EXPECT_DEATH( %s ) failed! (%s)\n\n", stmt, msg);
261 if (RK != DeathTest::RK_Unknown) {
262 std::fprintf(stderr, "child exit code: %d\n", DT.getChildExitCode());
264 if (!DT.getChildStdErr().empty()) {
265 std::fprintf(stderr, "---------- standard err ----------\n%s\n", DT.getChildStdErr().c_str());
267 if (!DT.getChildStdOut().empty()) {
268 std::fprintf(stderr, "---------- standard out ----------\n%s\n", DT.getChildStdOut().c_str());
270 return false;
272 switch (RK) {
273 case DeathTest::RK_MatchFound:
274 return true;
275 case DeathTest::RK_SetupFailure:
276 return OnFailure("child failed to setup test environment");
277 case DeathTest::RK_Unknown:
278 return OnFailure("reason unknown");
279 case DeathTest::RK_DidNotDie:
280 return OnFailure("child did not die");
281 case DeathTest::RK_MatchFailure:
282 return OnFailure("matcher failed");
284 assert(false && "unreachable");
287 template <class Func>
288 inline bool ExpectDeath(const char* stmt, Func&& func) {
289 return ExpectDeath(stmt, func, AnyMatcher);
292 /// Assert that the specified expression throws a libc++ debug exception.
293 #define EXPECT_DEATH(...) assert((ExpectDeath(#__VA_ARGS__, [&]() { __VA_ARGS__; } )))
295 #define EXPECT_DEATH_MATCHES(Matcher, ...) assert((ExpectDeath(#__VA_ARGS__, [&]() { __VA_ARGS__; }, Matcher)))
297 #endif // TEST_SUPPORT_DEBUG_MODE_HELPER_H