You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@logging.apache.org by sw...@apache.org on 2026/08/26 06:43:10 UTC

(logging-log4cxx) 01/01: Reduce overhead when formatting MDC values into a message

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

swebb2066 pushed a commit to branch reduce_mdc_formating_overhead
in repository https://gitbox.apache.org/repos/asf/logging-log4cxx.git

commit 4b9290dd1e3b2f0e8bc3e7f11e31adffbf88eadd
Author: Stephen Webb <sw...@gmail.com>
AuthorDate: Wed Aug 26 16:42:19 2026 +1000

    Reduce overhead when formatting MDC values into a message
---
 src/main/cpp/mdcpatternconverter.cpp | 19 +++++++++++++++----
 src/test/cpp/mdctestcase.cpp         | 11 +++++++++++
 2 files changed, 26 insertions(+), 4 deletions(-)

diff --git a/src/main/cpp/mdcpatternconverter.cpp b/src/main/cpp/mdcpatternconverter.cpp
index c3386117..aafd4a3a 100644
--- a/src/main/cpp/mdcpatternconverter.cpp
+++ b/src/main/cpp/mdcpatternconverter.cpp
@@ -83,11 +83,22 @@ void MDCPatternConverter::format( LOG4CXX_FORMAT_EVENT_FORMAL_PARAMETERS ) const
 	if (!m_priv->style.empty()) // In a quoted context?
 	{
 		auto quote = m_priv->style.front();
-		size_t endIndex;
-		while ((endIndex = toAppendTo.find(quote, startIndex)) != toAppendTo.npos)
+		if (toAppendTo.find(quote, startIndex) != toAppendTo.npos)
 		{
-			toAppendTo.insert(endIndex + 1, 1, quote);
-			startIndex = endIndex + 2;
+			// Duplicate each quote character in a single linear pass:
+			// repeated single-character insert() shifts the tail of the
+			// output buffer on every quote, which is quadratic in the
+			// (attacker-controllable) MDC content length.
+			LogString input = toAppendTo.substr(startIndex);
+			toAppendTo.resize(startIndex);
+			size_t endIndex, index = 0;
+			while ((endIndex = input.find(quote, index)) != input.npos)
+			{
+				toAppendTo.append(input, index, endIndex - index + 1);
+				toAppendTo += quote;
+				index = endIndex + 1;
+			}
+			toAppendTo.append(input, index, LogString::npos);
 		}
 	}
 }
diff --git a/src/test/cpp/mdctestcase.cpp b/src/test/cpp/mdctestcase.cpp
index ccefcd6a..afdc4049 100644
--- a/src/test/cpp/mdctestcase.cpp
+++ b/src/test/cpp/mdctestcase.cpp
@@ -36,6 +36,7 @@ LOGUNIT_CLASS(MDCTestCase)
 	LOGUNIT_TEST(test1);
 	LOGUNIT_TEST(test2);
 	LOGUNIT_TEST(test3);
+	LOGUNIT_TEST(test4);
 	LOGUNIT_TEST_SUITE_END();
 
 public:
@@ -91,6 +92,16 @@ public:
 		converter.format(e, output);
 		LOGUNIT_ASSERT_EQUAL(LOG4CXX_STR(""), output);
 	}
+
+	/// A quote character in MDC content must be doubled in a quoted context.
+	void test4()
+	{
+		MDC item1("key1", "it's");
+		LogString output;
+		PatternLayout l{ LOG4CXX_STR("%J{'}") };
+		l.format(output, std::make_shared<spi::LoggingEvent>(LOG4CXX_STR("MDC.LayoutTest"), Level::getInfo(), LOG4CXX_STR("Message"), spi::LocationInfo::getLocationUnavailable()));
+		LOGUNIT_ASSERT_EQUAL(LOG4CXX_STR("{\"key1\":\"it''s\"}"), output);
+	}
 };
 
 LOGUNIT_TEST_SUITE_REGISTRATION(MDCTestCase);