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 <[email protected]> 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);
