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