[libcxx-commits] [libcxx] DRAFT [libc++][hardening] In production hardening modes, trap rather than abort (PR #78561)

Louis Dionne via libcxx-commits libcxx-commits at lists.llvm.org
Thu Jan 18 13:05:53 PST 2024


================
@@ -27,37 +28,70 @@
 #include "test_allocator.h"
 
 #if TEST_STD_VER < 11
-# error "C++11 or greater is required to use this header"
+#  error "C++11 or greater is required to use this header"
 #endif
 
 struct AssertionInfoMatcher {
-  static const int any_line = -1;
+  // When printing the assertion message to `stderr`, delimit it with a marker to make it easier to match the message
+  // later.
+  static constexpr const char* Marker = "###";
+
+  static const int any_line             = -1;
   static constexpr const char* any_file = "*";
-  static constexpr const char* any_msg = "*";
+  static constexpr const char* any_msg  = "*";
 
-  constexpr AssertionInfoMatcher() : is_empty_(true), msg_(any_msg, __builtin_strlen(any_msg)), file_(any_file, __builtin_strlen(any_file)), line_(any_line) { }
+  constexpr AssertionInfoMatcher()
+      : msg_(any_msg, __builtin_strlen(any_msg)), file_(any_file, __builtin_strlen(any_file)), line_(any_line) {}
   constexpr AssertionInfoMatcher(const char* msg, const char* file = any_file, int line = any_line)
-    : is_empty_(false), msg_(msg, __builtin_strlen(msg)), file_(file, __builtin_strlen(file)), line_(line) {}
+      : is_empty_(false), msg_(msg, __builtin_strlen(msg)), file_(file, __builtin_strlen(file)), line_(line) {}
+
+  bool CheckMatchInOutput(const std::string& output, std::string& error) const {
+    // Extract information from the error message. This has to stay synchronized with how we format assertions in the
+    // library.
+    std::regex message_format(".*###\\n(.*):(\\d+): assertion (.*) failed: (.*)\\n###");
+
+    std::smatch match_result;
+    bool has_match = std::regex_match(output, match_result, message_format);
+    assert(has_match);
+    assert(match_result.size() == 5);
+
+    const std::string& file = match_result[1];
+    int line                = std::stoi(match_result[2]);
+    // Omitting `expression` in `match_result[3]`
+    const std::string& failure_reason = match_result[4];
+
+    bool result = Matches(file, line, failure_reason);
+    if (!result) {
+      error = FormatMatchingError(file, line, failure_reason);
+    }
+    return result;
+  }
 
-  bool Matches(char const* file, int line, char const* message) const {
-    assert(!empty() && "empty matcher");
+  bool Matches(const std::string& file, int line, const std::string& message) const {
+    assert(!empty() && "Empty matcher");
+    return CheckLineMatches(line) && CheckFileMatches(file) && CheckMessageMatches(message);
+  }
 
-    if (CheckLineMatches(line) && CheckFileMatches(file) && CheckMessageMatches(message))
-        return true;
-    // Write to stdout because that's the file descriptor captured by the parent
-    // process.
-    std::printf("Failed to match assertion info!\n%s\nVS\n%s:%d (%s)\n", ToString().data(), file, line, message);
-    return false;
+  std::string FormatMatchingError(const std::string& file, int line, const std::string& message) const {
+    std::stringstream output;
+    output                                                                 //
+        << "Expected message:   '" << msg_.data() << "'\n"                 //
+        << "Actual message:     '" << message.c_str() << "'\n"             //
+        << "Expected location:   " << FormatLocation(file_, line_) << "\n" //
+        << "Actual location:     " << FormatLocation(file, line) << "\n";
+    return output.str();
   }
 
-  std::string ToString() const {
-    std::string result = "msg = \""; result += msg_; result += "\"\n";
-    result += "line = " + (line_ == any_line ? "'*'" : std::to_string(line_)) + "\n";
-    result += "file = " + (file_ == any_file ? "'*'" : std::string(file_));
+  static std::string FormatLocation(std::string_view file, int line) {
+    std::string result;
+    result += (file == any_file ? "*" : std::string(file)) + ":";
+    result += (line == any_line ? "*" : std::to_string(line));
     return result;
   }
 
   bool empty() const { return is_empty_; }
+  bool IsAnyMatcher() const { return msg_ == any_msg && file_ == any_file && line_ == any_line; }
----------------
ldionne wrote:

I think this is unused now.

https://github.com/llvm/llvm-project/pull/78561


More information about the libcxx-commits mailing list