blob: ed111ab127ce797d3c0a44fa4f2468a264a32505 [file] [log] [blame]
Eric Fiselier780b51d2016-12-28 05:53:01 +00001//===----------------------------------------------------------------------===//
2//
Chandler Carruth57b08b02019-01-19 10:56:40 +00003// 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
Eric Fiselier780b51d2016-12-28 05:53:01 +00006//
7//===----------------------------------------------------------------------===//
8
9#ifndef TEST_SUPPORT_DEBUG_MODE_HELPER_H
10#define TEST_SUPPORT_DEBUG_MODE_HELPER_H
11
12#ifndef _LIBCPP_DEBUG
13#error _LIBCPP_DEBUG must be defined before including this header
14#endif
Eric Fiselier780b51d2016-12-28 05:53:01 +000015
16#include <ciso646>
17#ifndef _LIBCPP_VERSION
Eric Fiseliercc703de2019-03-18 22:12:09 +000018#error "This header may only be used for libc++ tests"
Eric Fiselier780b51d2016-12-28 05:53:01 +000019#endif
20
21#include <__debug>
22#include <utility>
23#include <cstddef>
24#include <cstdlib>
25#include <cassert>
Eric Fiselier61b302f2019-03-18 21:50:12 +000026#include <string_view>
27#include <sstream>
28#include <iostream>
Eric Fiselier780b51d2016-12-28 05:53:01 +000029
Eric Fiselier61b302f2019-03-18 21:50:12 +000030#include <unistd.h>
31#include <sys/wait.h>
Eric Fiselier780b51d2016-12-28 05:53:01 +000032#include "test_macros.h"
33#include "assert_checkpoint.h"
34#include "test_allocator.h"
35
Eric Fiselier61b302f2019-03-18 21:50:12 +000036#if TEST_STD_VER < 11
37# error "C++11 or greater is required to use this header"
Eric Fiselier780b51d2016-12-28 05:53:01 +000038#endif
39
Eric Fiselier61b302f2019-03-18 21:50:12 +000040struct DebugInfoMatcher {
41 static const int any_line = -1;
42 static constexpr const char* any_file = "*";
43 static constexpr const char* any_msg = "*";
Eric Fiselier780b51d2016-12-28 05:53:01 +000044
Eric Fiseliercc703de2019-03-18 22:12:09 +000045 constexpr DebugInfoMatcher() : is_empty(true), msg(any_msg, __builtin_strlen(any_msg)), file(any_file, __builtin_strlen(any_file)), line(any_line) { }
Eric Fiselier61b302f2019-03-18 21:50:12 +000046 constexpr DebugInfoMatcher(const char* msg, const char* file = any_file, int line = any_line)
Eric Fiseliercc703de2019-03-18 22:12:09 +000047 : is_empty(false), msg(msg, __builtin_strlen(msg)), file(file, __builtin_strlen(file)), line(line) {}
Eric Fiselier780b51d2016-12-28 05:53:01 +000048
Eric Fiselier61b302f2019-03-18 21:50:12 +000049 bool Matches(std::__libcpp_debug_info const& got) const {
50 assert(!empty() && "empty matcher");
51
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::cout << "Failed to match debug info!\n"
58 << ToString() << "\n"
59 << "VS\n"
60 << got.what() << "\n";
61 return false;
62 }
63
64 std::string ToString() const {
65 std::stringstream ss;
66 ss << "msg = \"" << msg << "\"\n"
67 << "line = " << (line == any_line ? "'*'" : std::to_string(line)) << "\n"
68 << "file = " << (file == any_file ? "'*'" : any_file) << "";
69 return ss.str();
70 }
71
72 bool empty() const { return is_empty; }
73private:
74 bool CheckLineMatches(int got_line) const {
75 if (line == any_line)
76 return true;
77 return got_line == line;
78 }
79
80 bool CheckFileMatches(std::string_view got_file) const {
81 assert(!empty() && "empty matcher");
82 if (file == any_file)
83 return true;
84 std::size_t found_at = got_file.find(file);
85 if (found_at == std::string_view::npos)
86 return false;
87 // require the match start at the beginning of the file or immediately after
88 // a directory separator.
89 if (found_at != 0) {
90 char last_char = got_file[found_at - 1];
91 if (last_char != '/' && last_char != '\\')
92 return false;
93 }
94 // require the match goes until the end of the string.
95 return got_file.substr(found_at) == file;
96 }
97
98 bool CheckMessageMatches(std::string_view got_msg) const {
99 assert(!empty() && "empty matcher");
100 if (msg == any_msg)
101 return true;
102 std::size_t found_at = got_msg.find(msg);
103 if (found_at == std::string_view::npos)
104 return false;
105 // Allow any match
Eric Fiselier780b51d2016-12-28 05:53:01 +0000106 return true;
107 }
Eric Fiselier780b51d2016-12-28 05:53:01 +0000108private:
Eric Fiselier61b302f2019-03-18 21:50:12 +0000109 bool is_empty;
110 std::string_view msg;
111 std::string_view file;
112 int line;
Eric Fiselier780b51d2016-12-28 05:53:01 +0000113};
114
Eric Fiselier61b302f2019-03-18 21:50:12 +0000115static constexpr DebugInfoMatcher AnyMatcher(DebugInfoMatcher::any_msg);
116
117inline DebugInfoMatcher& GlobalMatcher() {
118 static DebugInfoMatcher GMatch;
119 return GMatch;
120}
121
122struct DeathTest {
123 enum ResultKind {
124 RK_DidNotDie, RK_MatchFound, RK_MatchFailure, RK_SetupFailure, RK_Unknown
125 };
126
127 static const char* ResultKindToString(ResultKind RK) {
128#define CASE(K) case K: return #K
129 switch (RK) {
130 CASE(RK_MatchFailure);
131 CASE(RK_DidNotDie);
132 CASE(RK_SetupFailure);
133 CASE(RK_MatchFound);
134 CASE(RK_Unknown);
135 }
136 return "not a result kind";
137 }
138
139 static bool IsValidResultKind(int val) {
140 return val >= RK_DidNotDie && val <= RK_Unknown;
141 }
142
143 TEST_NORETURN static void DeathTestDebugHandler(std::__libcpp_debug_info const& info) {
144 assert(!GlobalMatcher().empty());
145 if (GlobalMatcher().Matches(info)) {
146 std::exit(RK_MatchFound);
147 }
148 std::exit(RK_MatchFailure);
149 }
150
151
152 DeathTest(DebugInfoMatcher const& Matcher) : matcher_(Matcher) {}
153
154 template <class Func>
155 ResultKind Run(Func&& f) {
156 int pipe_res = pipe(stdout_pipe_fd_);
157 assert(pipe_res != -1 && "failed to create pipe");
158 pipe_res = pipe(stderr_pipe_fd_);
159 assert(pipe_res != -1 && "failed to create pipe");
160 pid_t child_pid = fork();
161 assert(child_pid != -1 &&
162 "failed to fork a process to perform a death test");
163 child_pid_ = child_pid;
164 if (child_pid_ == 0) {
165 RunForChild(std::forward<Func>(f));
166 assert(false && "unreachable");
167 }
168 return RunForParent();
169 }
170
171 int getChildExitCode() const { return exit_code_; }
172 std::string const& getChildStdOut() const { return stdout_from_child_; }
173 std::string const& getChildStdErr() const { return stderr_from_child_; }
174private:
175 template <class Func>
176 TEST_NORETURN void RunForChild(Func&& f) {
177 close(GetStdOutReadFD()); // don't need to read from the pipe in the child.
178 close(GetStdErrReadFD());
179 auto DupFD = [](int DestFD, int TargetFD) {
180 int dup_result = dup2(DestFD, TargetFD);
181 if (dup_result == -1)
182 std::exit(RK_SetupFailure);
183 };
184 DupFD(GetStdOutWriteFD(), STDOUT_FILENO);
185 DupFD(GetStdErrWriteFD(), STDERR_FILENO);
186
187 GlobalMatcher() = matcher_;
188 std::__libcpp_set_debug_function(&DeathTestDebugHandler);
189 f();
190 std::exit(RK_DidNotDie);
191 }
192
193 static std::string ReadChildIOUntilEnd(int FD) {
194 std::string error_msg;
195 char buffer[256];
196 int num_read;
197 do {
198 while ((num_read = read(FD, buffer, 255)) > 0) {
199 buffer[num_read] = '\0';
200 error_msg += buffer;
201 }
202 } while (num_read == -1 && errno == EINTR);
203 return error_msg;
204 }
205
206 void CaptureIOFromChild() {
207 close(GetStdOutWriteFD()); // no need to write from the parent process
208 close(GetStdErrWriteFD());
209 stdout_from_child_ = ReadChildIOUntilEnd(GetStdOutReadFD());
210 stderr_from_child_ = ReadChildIOUntilEnd(GetStdErrReadFD());
211 close(GetStdOutReadFD());
212 close(GetStdErrReadFD());
213 }
214
215 ResultKind RunForParent() {
216 CaptureIOFromChild();
217
218 int status_value;
219 pid_t result = waitpid(child_pid_, &status_value, 0);
220 assert(result != -1 && "there is no child process to wait for");
221
222 if (WIFEXITED(status_value)) {
223 exit_code_ = WEXITSTATUS(status_value);
224 if (!IsValidResultKind(exit_code_))
225 return RK_Unknown;
226 return static_cast<ResultKind>(exit_code_);
227 }
228 return RK_Unknown;
229 }
230
231 DeathTest(DeathTest const&) = delete;
232 DeathTest& operator=(DeathTest const&) = delete;
233
234 int GetStdOutReadFD() const {
235 return stdout_pipe_fd_[0];
236 }
237
238 int GetStdOutWriteFD() const {
239 return stdout_pipe_fd_[1];
240 }
241
242 int GetStdErrReadFD() const {
243 return stderr_pipe_fd_[0];
244 }
245
246 int GetStdErrWriteFD() const {
247 return stderr_pipe_fd_[1];
248 }
249private:
250 DebugInfoMatcher matcher_;
251 pid_t child_pid_ = -1;
252 int exit_code_ = -1;
253 int stdout_pipe_fd_[2];
254 int stderr_pipe_fd_[2];
255 std::string stdout_from_child_;
256 std::string stderr_from_child_;
257};
258
259template <class Func>
260inline bool ExpectDeath(const char* stmt, Func&& func, DebugInfoMatcher Matcher) {
261 DeathTest DT(Matcher);
262 DeathTest::ResultKind RK = DT.Run(func);
263 auto OnFailure = [&](const char* msg) {
264 std::cerr << "EXPECT_DEATH( " << stmt << " ) failed! (" << msg << ")\n\n";
265 if (RK != DeathTest::RK_Unknown) {
266 std::cerr << "child exit code: " << DT.getChildExitCode() << "\n";
267 }
268 if (!DT.getChildStdErr().empty()) {
269 std::cerr << "---------- standard err ----------\n";
270 std::cerr << DT.getChildStdErr() << "\n";
271 }
272 if (!DT.getChildStdOut().empty()) {
273 std::cerr << "---------- standard out ----------\n";
274 std::cerr << DT.getChildStdOut() << "\n";
275 }
276 return false;
277 };
278 switch (RK) {
279 case DeathTest::RK_MatchFound:
280 return true;
281 case DeathTest::RK_SetupFailure:
282 return OnFailure("child failed to setup test environment");
283 case DeathTest::RK_Unknown:
284 return OnFailure("reason unknown");
285 case DeathTest::RK_DidNotDie:
286 return OnFailure("child did not die");
287 case DeathTest::RK_MatchFailure:
288 return OnFailure("matcher failed");
289 }
290}
291
292template <class Func>
293inline bool ExpectDeath(const char* stmt, Func&& func) {
294 return ExpectDeath(stmt, func, AnyMatcher);
295}
296
297/// Assert that the specified expression throws a libc++ debug exception.
298#define EXPECT_DEATH(...) assert((ExpectDeath(#__VA_ARGS__, [&]() { __VA_ARGS__; } )))
299
300#define EXPECT_DEATH_MATCHES(Matcher, ...) assert((ExpectDeath(#__VA_ARGS__, [&]() { __VA_ARGS__; }, Matcher)))
Eric Fiselier780b51d2016-12-28 05:53:01 +0000301
302#endif // TEST_SUPPORT_DEBUG_MODE_HELPER_H