xref: /llvm-project/libcxx/test/support/check_assertion.h (revision 36d8b449cfc9850513bb2ed6c07b5b8cc9f1ae3a)
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 
40   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)
42     : is_empty_(false), msg_(msg, __builtin_strlen(msg)), file_(file, __builtin_strlen(file)), line_(line) {}
43 
44   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 
55   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 
62   bool empty() const { return is_empty_; }
63 private:
64   bool CheckLineMatches(int got_line) const {
65     if (line_ == any_line)
66       return true;
67     return got_line == line_;
68   }
69 
70   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 
88   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 
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 
117   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 
129   static bool IsValidResultKind(int val) {
130     return val >= RK_DidNotDie && val <= RK_Unknown;
131   }
132 
133   DeathTest(AssertionInfoMatcher const& Matcher) : matcher_(Matcher) {}
134 
135   template <class Func>
136   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 
152   int getChildExitCode() const { return exit_code_; }
153   std::string const& getChildStdOut() const { return stdout_from_child_; }
154   std::string const& getChildStdErr() const { return stderr_from_child_; }
155 private:
156   template <class Func>
157   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 
173   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 
186   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 
195   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 
214   int GetStdOutReadFD() const {
215     return stdout_pipe_fd_[0];
216   }
217 
218   int GetStdOutWriteFD() const {
219     return stdout_pipe_fd_[1];
220   }
221 
222   int GetStdErrReadFD() const {
223     return stderr_pipe_fd_[0];
224   }
225 
226   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 
239 void std::__libcpp_verbose_abort(char const* format, ...) {
240   // Extract information from the error message. This has to stay synchronized with
241   // how we format assertions in the library.
242   va_list list;
243   va_start(list, format);
244   char const* file = va_arg(list, char const*);
245   int line = va_arg(list, int);
246   char const* expression = va_arg(list, char const*); (void)expression;
247   char const* message = va_arg(list, char const*);
248   va_end(list);
249 
250   if (GlobalMatcher().Matches(file, line, message)) {
251     std::exit(DeathTest::RK_MatchFound);
252   }
253   std::exit(DeathTest::RK_MatchFailure);
254 }
255 
256 template <class Func>
257 inline bool ExpectDeath(const char* stmt, Func&& func, AssertionInfoMatcher Matcher) {
258   DeathTest DT(Matcher);
259   DeathTest::ResultKind RK = DT.Run(func);
260   auto OnFailure = [&](const char* msg) {
261     std::fprintf(stderr, "EXPECT_DEATH( %s ) failed! (%s)\n\n", stmt, msg);
262     if (RK != DeathTest::RK_Unknown) {
263       std::fprintf(stderr, "child exit code: %d\n", DT.getChildExitCode());
264     }
265     if (!DT.getChildStdErr().empty()) {
266       std::fprintf(stderr, "---------- standard err ----------\n%s\n", DT.getChildStdErr().c_str());
267     }
268     if (!DT.getChildStdOut().empty()) {
269       std::fprintf(stderr, "---------- standard out ----------\n%s\n", DT.getChildStdOut().c_str());
270     }
271     return false;
272   };
273   switch (RK) {
274   case DeathTest::RK_MatchFound:
275     return true;
276   case DeathTest::RK_SetupFailure:
277     return OnFailure("child failed to setup test environment");
278   case DeathTest::RK_Unknown:
279       return OnFailure("reason unknown");
280   case DeathTest::RK_DidNotDie:
281       return OnFailure("child did not die");
282   case DeathTest::RK_MatchFailure:
283       return OnFailure("matcher failed");
284   }
285   assert(false && "unreachable");
286 }
287 
288 template <class Func>
289 inline bool ExpectDeath(const char* stmt, Func&& func) {
290   return ExpectDeath(stmt, func, AnyMatcher);
291 }
292 
293 /// Assert that the specified expression throws a libc++ debug exception.
294 #define EXPECT_DEATH(...) assert((ExpectDeath(#__VA_ARGS__, [&]() { __VA_ARGS__; } )))
295 
296 #define EXPECT_DEATH_MATCHES(Matcher, ...) assert((ExpectDeath(#__VA_ARGS__, [&]() { __VA_ARGS__; }, Matcher)))
297 
298 #define TEST_LIBCPP_ASSERT_FAILURE(expr, message) assert((ExpectDeath(#expr, [&]() { (void)(expr); }, AssertionInfoMatcher(message))))
299 
300 #endif // TEST_SUPPORT_CHECK_ASSERTION_H
301