This is an automated email from the ASF dual-hosted git repository.

szaszm pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/nifi-minifi-cpp.git

commit 4be2c2e18ffe1867eab99d69dd41c4b2924dac8c
Author: Martin Zink <[email protected]>
AuthorDate: Tue Nov 18 12:35:02 2025 +0100

    MINIFICPP-2671 Various ASan fixes
    
     - fixing use-after-free in LogTestController::matchesRegex
     - fixing container-overflow in ConnectionCountingServer.cpp
     - fixing container-overflow in MockSplunkHEC
     - fixing stack-use-after-scope in UnfocusArchiveEntry.cpp
    
    Closes #2064
    
    Signed-off-by: Marton Szasz <[email protected]>
---
 extensions/libarchive/UnfocusArchiveEntry.cpp      |  7 ++---
 extensions/splunk/tests/MockSplunkHEC.h            |  3 +-
 .../tests/unit/AttributesToJSONTests.cpp           |  2 +-
 .../integration/ConnectionCountingServer.cpp       |  7 ++---
 libminifi/test/libtest/unit/TestBase.cpp           | 34 +++++++++++-----------
 libminifi/test/libtest/unit/TestBase.h             |  2 +-
 6 files changed, 26 insertions(+), 29 deletions(-)

diff --git a/extensions/libarchive/UnfocusArchiveEntry.cpp 
b/extensions/libarchive/UnfocusArchiveEntry.cpp
index 8b49fe2fe..eb94b693f 100644
--- a/extensions/libarchive/UnfocusArchiveEntry.cpp
+++ b/extensions/libarchive/UnfocusArchiveEntry.cpp
@@ -151,15 +151,14 @@ la_ssize_t 
UnfocusArchiveEntry::WriteCallback::write_cb(struct archive *, void *
 }
 
 int64_t UnfocusArchiveEntry::WriteCallback::operator()(const 
std::shared_ptr<io::OutputStream>& stream) const {
+  UnfocusArchiveEntryWriteData data;
+  data.stream = stream;
   auto output_archive = archive_write_unique_ptr{archive_write_new()};
   int64_t nlen = 0;
 
   archive_write_set_format(output_archive.get(), 
_archiveMetadata->archiveFormat);
 
-  UnfocusArchiveEntryWriteData data;
-  data.stream = stream;
-
-  archive_write_open(output_archive.get(), &data, ok_cb, write_cb, ok_cb);
+  archive_write_open(output_archive.get(), &data, nullptr, write_cb, nullptr); 
 // data must outlive the archive because it writes during free
 
   // Iterate entries & write from tmp file to archive
   std::array<char, BUFFER_SIZE> buf{};
diff --git a/extensions/splunk/tests/MockSplunkHEC.h 
b/extensions/splunk/tests/MockSplunkHEC.h
index 854153468..eb95f40c0 100644
--- a/extensions/splunk/tests/MockSplunkHEC.h
+++ b/extensions/splunk/tests/MockSplunkHEC.h
@@ -130,8 +130,7 @@ class AckIndexerHandler : public MockSplunkHandler {
 
  protected:
   bool handlePostImpl(struct mg_connection* conn) override {
-    std::vector<char> data;
-    data.reserve(2048);
+    auto data = std::vector<char>(2048);
     mg_read(conn, data.data(), 2048);
     rapidjson::Document post_data;
 
diff --git 
a/extensions/standard-processors/tests/unit/AttributesToJSONTests.cpp 
b/extensions/standard-processors/tests/unit/AttributesToJSONTests.cpp
index 1fd1c7de2..e3670eb73 100644
--- a/extensions/standard-processors/tests/unit/AttributesToJSONTests.cpp
+++ b/extensions/standard-processors/tests/unit/AttributesToJSONTests.cpp
@@ -67,7 +67,7 @@ class AttributesToJSONTestFixture {
   static void assertJSONAttributesFromLog(const 
std::unordered_map<std::string, std::optional<std::string>>& 
expected_attributes) {
     auto match = 
LogTestController::getInstance().matchesRegex("key:JSONAttributes value:(.*)");
     REQUIRE(match);
-    assertAttributes(expected_attributes, (*match)[1].str());
+    assertAttributes(expected_attributes, (*match)[1]);
   }
 
   void assertJSONAttributesFromFile(const std::unordered_map<std::string, 
std::optional<std::string>>& expected_attributes) {
diff --git a/libminifi/test/libtest/integration/ConnectionCountingServer.cpp 
b/libminifi/test/libtest/integration/ConnectionCountingServer.cpp
index 86baee859..6a1fc4409 100644
--- a/libminifi/test/libtest/integration/ConnectionCountingServer.cpp
+++ b/libminifi/test/libtest/integration/ConnectionCountingServer.cpp
@@ -64,12 +64,11 @@ void NumberedMethodResponder::saveConnectionId(struct 
mg_connection* conn) {
 
 bool ReverseBodyPostHandler::handlePost(CivetServer* /*server*/, struct 
mg_connection* conn) {
   saveConnectionId(conn);
-  std::vector<char> request_body;
-  request_body.reserve(2048);
-  size_t read_size = mg_read(conn, request_body.data(), 2048);
+  auto request_body = std::vector<char>(2048);
+  const size_t read_size = mg_read(conn, request_body.data(), 2048);
   assert(read_size < 2048);
   std::string response_body{request_body.begin(), request_body.begin() + 
gsl::narrow<std::vector<char>::difference_type>(read_size)};
-  std::reverse(std::begin(response_body), std::end(response_body));
+  std::ranges::reverse(response_body);
   mg_printf(conn, "HTTP/1.1 200 OK\r\n");
   mg_printf(conn, "Content-length: %zu\r\n", read_size);
   mg_printf(conn, "\r\n");
diff --git a/libminifi/test/libtest/unit/TestBase.cpp 
b/libminifi/test/libtest/unit/TestBase.cpp
index 525ce13c1..0cf593b34 100644
--- a/libminifi/test/libtest/unit/TestBase.cpp
+++ b/libminifi/test/libtest/unit/TestBase.cpp
@@ -126,27 +126,27 @@ bool LogTestController::contains(const 
std::function<std::string()>& log_string_
   return found;
 }
 
-std::optional<std::smatch> LogTestController::matchesRegex(const std::string& 
regex_str, std::chrono::milliseconds timeout, std::chrono::milliseconds 
sleep_interval) const {
+std::optional<std::vector<std::string>> LogTestController::matchesRegex(const 
std::string& regex_str, const std::chrono::milliseconds timeout, const 
std::chrono::milliseconds sleep_interval) const {
   if (regex_str.empty()) {
     return std::nullopt;
   }
-  auto start = std::chrono::steady_clock::now();
-  bool found = false;
-  bool timed_out = false;
-  std::regex matcher_regex(regex_str);
-  std::smatch match;
-  do {
-    std::string str = getLogs();
-    found = std::regex_search(str, match, matcher_regex);
-    auto now = std::chrono::steady_clock::now();
-    timed_out = (now - start > timeout);
-    if (!found && !timed_out) {
-      std::this_thread::sleep_for(sleep_interval);
+  const auto start = std::chrono::steady_clock::now();
+  const std::regex matcher_regex(regex_str);
+  while (true) {
+    const std::string logs = getLogs();
+    if (std::smatch match; std::regex_search(logs, match, matcher_regex)) {
+      std::vector<std::string> results;
+      results.reserve(match.size());
+      for (const auto& sub_match : match) {
+        results.push_back(sub_match.str());
+      }
+      return std::make_optional(std::move(results));
     }
-  } while (!found && !timed_out);
-
-  logger_->log_info("{} {} in log output.", found ? "Successfully matched 
regex" : "Failed to match regex", regex_str);
-  return found ? std::make_optional<std::smatch>(match) : std::nullopt;
+    if (std::chrono::steady_clock::now() - start > timeout) {
+      return std::nullopt;
+    }
+    std::this_thread::sleep_for(sleep_interval);
+  }
 }
 
 size_t LogTestController::countOccurrences(const std::string& pattern) const {
diff --git a/libminifi/test/libtest/unit/TestBase.h 
b/libminifi/test/libtest/unit/TestBase.h
index 57e2b03c3..e8f48832d 100644
--- a/libminifi/test/libtest/unit/TestBase.h
+++ b/libminifi/test/libtest/unit/TestBase.h
@@ -135,7 +135,7 @@ class LogTestController {
       std::chrono::milliseconds timeout = std::chrono::seconds(3),
       std::chrono::milliseconds sleep_interval = 
std::chrono::milliseconds(200));
 
-  std::optional<std::smatch> matchesRegex(const std::string &regex_str,
+  std::optional<std::vector<std::string>> matchesRegex(const std::string 
&regex_str,
                 std::chrono::milliseconds timeout = std::chrono::seconds(3),
                 std::chrono::milliseconds sleep_interval = 
std::chrono::milliseconds(200)) const;
 

Reply via email to