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

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


The following commit(s) were added to refs/heads/master by this push:
     new e20cab01 Improve robustness when logging large message strings (#593)
e20cab01 is described below

commit e20cab0192fed4c53142bd5656644877f41baba1
Author: Stephen Webb <[email protected]>
AuthorDate: Fri Feb 13 10:01:22 2026 +1100

    Improve robustness when logging large message strings (#593)
    
    * Add a compiler warning when the deprecated method is used
    
    * Make MDC JSON pattern layout formatting skip entries that exceed the 
maximum field length
    
    * Add deprecation status to html docs
---
 src/fuzzers/cpp/PatternParserFuzzer.cpp            |  9 +-----
 src/main/cpp/classnamepatternconverter.cpp         |  6 ----
 src/main/cpp/filelocationpatternconverter.cpp      |  3 +-
 src/main/cpp/formattinginfo.cpp                    |  4 ++-
 src/main/cpp/fulllocationpatternconverter.cpp      |  3 +-
 src/main/cpp/integerpatternconverter.cpp           |  3 +-
 src/main/cpp/levelpatternconverter.cpp             |  3 +-
 src/main/cpp/linelocationpatternconverter.cpp      |  3 +-
 src/main/cpp/lineseparatorpatternconverter.cpp     |  3 +-
 src/main/cpp/loggerpatternconverter.cpp            |  6 ----
 src/main/cpp/mdcpatternconverter.cpp               | 34 +++++++++++++++-------
 src/main/cpp/messagepatternconverter.cpp           | 10 +++++--
 src/main/cpp/methodlocationpatternconverter.cpp    |  3 +-
 src/main/cpp/ndcpatternconverter.cpp               | 14 +++++++--
 src/main/cpp/patternconverter.cpp                  |  9 ++++++
 src/main/cpp/patternlayout.cpp                     | 26 ++++-------------
 src/main/cpp/patternparser.cpp                     | 29 ++++++++++--------
 src/main/cpp/propertiespatternconverter.cpp        |  3 +-
 src/main/cpp/rollingpolicybase.cpp                 | 19 +++---------
 src/main/cpp/shortfilelocationpatternconverter.cpp |  3 +-
 src/main/cpp/threadpatternconverter.cpp            |  3 +-
 src/main/cpp/threadusernamepatternconverter.cpp    |  3 +-
 .../cpp/throwableinformationpatternconverter.cpp   |  6 ++--
 .../include/log4cxx/pattern/patternconverter.h     | 11 +++++++
 src/main/include/log4cxx/pattern/patternparser.h   | 19 ++++++++++--
 .../log4cxx/private/patternconverter_priv.h        |  6 ++++
 .../log4cxx/private/rollingpolicybase_priv.h       |  5 ----
 .../include/log4cxx/rolling/rollingpolicybase.h    |  1 -
 src/test/cpp/mdctestcase.cpp                       | 17 +++++++++--
 src/test/cpp/ndctestcase.cpp                       | 15 ++++++++++
 src/test/cpp/pattern/patternparsertestcase.cpp     | 13 +++------
 src/test/cpp/patternlayouttest.cpp                 | 17 +++++++++++
 src/test/cpp/rolling/filenamepatterntestcase.cpp   | 13 +++------
 33 files changed, 182 insertions(+), 140 deletions(-)

diff --git a/src/fuzzers/cpp/PatternParserFuzzer.cpp 
b/src/fuzzers/cpp/PatternParserFuzzer.cpp
index 4b1f2865..a5d96db1 100644
--- a/src/fuzzers/cpp/PatternParserFuzzer.cpp
+++ b/src/fuzzers/cpp/PatternParserFuzzer.cpp
@@ -131,14 +131,7 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, 
size_t size) {
        log4cxx::spi::LoggingEventPtr event = log4cxx::spi::LoggingEventPtr(
                new log4cxx::spi::LoggingEvent(
                        logger, level, contentLogString, LOG4CXX_LOCATION));
-
-
-       log4cxx::helpers::Pool p;
-       PatternMap patternMap = getFormatSpecifiers();
-       std::vector<PatternConverterPtr> converters;
-       std::vector<FormattingInfoPtr> fields;
-
-       PatternParser::parse(patternLogString, converters, fields, patternMap);
+       auto converters = PatternParser::parse(patternLogString, 
getFormatSpecifiers());
 
        return 0;
 }
diff --git a/src/main/cpp/classnamepatternconverter.cpp 
b/src/main/cpp/classnamepatternconverter.cpp
index 27226aaf..4af44420 100644
--- a/src/main/cpp/classnamepatternconverter.cpp
+++ b/src/main/cpp/classnamepatternconverter.cpp
@@ -37,12 +37,6 @@ ClassNamePatternConverter::ClassNamePatternConverter(
 PatternConverterPtr ClassNamePatternConverter::newInstance(
        const std::vector<LogString>& options)
 {
-       if (options.size() == 0)
-       {
-               static WideLife<PatternConverterPtr> def = 
std::make_shared<ClassNamePatternConverter>(options);
-               return def;
-       }
-
        return std::make_shared<ClassNamePatternConverter>(options);
 }
 
diff --git a/src/main/cpp/filelocationpatternconverter.cpp 
b/src/main/cpp/filelocationpatternconverter.cpp
index efb40664..93a9e0d0 100644
--- a/src/main/cpp/filelocationpatternconverter.cpp
+++ b/src/main/cpp/filelocationpatternconverter.cpp
@@ -35,8 +35,7 @@ FileLocationPatternConverter::FileLocationPatternConverter() :
 PatternConverterPtr FileLocationPatternConverter::newInstance(
        const std::vector<LogString>& /* options */ )
 {
-       static WideLife<PatternConverterPtr> instance = 
std::make_shared<FileLocationPatternConverter>();
-       return instance;
+       return std::make_shared<FileLocationPatternConverter>();
 }
 
 void FileLocationPatternConverter::format(
diff --git a/src/main/cpp/formattinginfo.cpp b/src/main/cpp/formattinginfo.cpp
index 2f62545a..56ef54a8 100644
--- a/src/main/cpp/formattinginfo.cpp
+++ b/src/main/cpp/formattinginfo.cpp
@@ -79,7 +79,9 @@ FormattingInfoPtr FormattingInfo::getDefault()
  */
 void FormattingInfo::format(const int fieldStart, LogString& buffer) const
 {
-       int rawLength = int(buffer.length() - fieldStart);
+       if (INT_MAX < buffer.length())
+               return;
+       int rawLength = static_cast<int>(buffer.length()) - fieldStart;
 
        if (rawLength > m_priv->maxLength)
        {
diff --git a/src/main/cpp/fulllocationpatternconverter.cpp 
b/src/main/cpp/fulllocationpatternconverter.cpp
index 50505275..ffec5abf 100644
--- a/src/main/cpp/fulllocationpatternconverter.cpp
+++ b/src/main/cpp/fulllocationpatternconverter.cpp
@@ -37,8 +37,7 @@ FullLocationPatternConverter::FullLocationPatternConverter() :
 PatternConverterPtr FullLocationPatternConverter::newInstance(
        const std::vector<LogString>& /* options */)
 {
-       static WideLife<PatternConverterPtr> instance = 
std::make_shared<FullLocationPatternConverter>();
-       return instance;
+       return std::make_shared<FullLocationPatternConverter>();
 }
 
 void FullLocationPatternConverter::format(
diff --git a/src/main/cpp/integerpatternconverter.cpp 
b/src/main/cpp/integerpatternconverter.cpp
index 3e8d3c58..6e9d3ae3 100644
--- a/src/main/cpp/integerpatternconverter.cpp
+++ b/src/main/cpp/integerpatternconverter.cpp
@@ -35,8 +35,7 @@ IntegerPatternConverter::IntegerPatternConverter() :
 PatternConverterPtr IntegerPatternConverter::newInstance(
        const std::vector<LogString>& /* options */)
 {
-       static WideLife<PatternConverterPtr> instance = 
std::make_shared<IntegerPatternConverter>();
-       return instance;
+       return std::make_shared<IntegerPatternConverter>();
 }
 
 void IntegerPatternConverter::format(
diff --git a/src/main/cpp/levelpatternconverter.cpp 
b/src/main/cpp/levelpatternconverter.cpp
index 137543fc..725a8cb0 100644
--- a/src/main/cpp/levelpatternconverter.cpp
+++ b/src/main/cpp/levelpatternconverter.cpp
@@ -38,8 +38,7 @@ LevelPatternConverter::LevelPatternConverter() :
 PatternConverterPtr LevelPatternConverter::newInstance(
        const std::vector<LogString>& /* options */)
 {
-       static WideLife<PatternConverterPtr> def = 
std::make_shared<LevelPatternConverter>();
-       return def;
+       return std::make_shared<LevelPatternConverter>();
 }
 
 void LevelPatternConverter::format(
diff --git a/src/main/cpp/linelocationpatternconverter.cpp 
b/src/main/cpp/linelocationpatternconverter.cpp
index bf1f42f9..693611fc 100644
--- a/src/main/cpp/linelocationpatternconverter.cpp
+++ b/src/main/cpp/linelocationpatternconverter.cpp
@@ -37,8 +37,7 @@ LineLocationPatternConverter::LineLocationPatternConverter() :
 PatternConverterPtr LineLocationPatternConverter::newInstance(
        const std::vector<LogString>& /* options */)
 {
-       static WideLife<PatternConverterPtr> instance = 
std::make_shared<LineLocationPatternConverter>();
-       return instance;
+       return std::make_shared<LineLocationPatternConverter>();
 }
 
 void LineLocationPatternConverter::format(
diff --git a/src/main/cpp/lineseparatorpatternconverter.cpp 
b/src/main/cpp/lineseparatorpatternconverter.cpp
index 871ccaec..63cfc540 100644
--- a/src/main/cpp/lineseparatorpatternconverter.cpp
+++ b/src/main/cpp/lineseparatorpatternconverter.cpp
@@ -36,8 +36,7 @@ 
LineSeparatorPatternConverter::LineSeparatorPatternConverter() :
 PatternConverterPtr LineSeparatorPatternConverter::newInstance(
        const std::vector<LogString>& /* options */)
 {
-       static WideLife<PatternConverterPtr> instance = 
std::make_shared<LineSeparatorPatternConverter>();
-       return instance;
+       return std::make_shared<LineSeparatorPatternConverter>();
 }
 
 void LineSeparatorPatternConverter::format(
diff --git a/src/main/cpp/loggerpatternconverter.cpp 
b/src/main/cpp/loggerpatternconverter.cpp
index 70e9aa1b..326390e8 100644
--- a/src/main/cpp/loggerpatternconverter.cpp
+++ b/src/main/cpp/loggerpatternconverter.cpp
@@ -37,12 +37,6 @@ LoggerPatternConverter::LoggerPatternConverter(
 PatternConverterPtr LoggerPatternConverter::newInstance(
        const std::vector<LogString>& options)
 {
-       if (options.size() == 0)
-       {
-               static WideLife<PatternConverterPtr> def = 
std::make_shared<LoggerPatternConverter>(options);
-               return def;
-       }
-
        return std::make_shared<LoggerPatternConverter>(options);
 }
 
diff --git a/src/main/cpp/mdcpatternconverter.cpp 
b/src/main/cpp/mdcpatternconverter.cpp
index 25db86b8..a70bc69e 100644
--- a/src/main/cpp/mdcpatternconverter.cpp
+++ b/src/main/cpp/mdcpatternconverter.cpp
@@ -38,10 +38,7 @@ PatternConverterPtr MDCPatternConverter::newInstance(
        const std::vector<LogString>& options)
 {
        if (options.empty())
-       {
-               static helpers::WideLife<PatternConverterPtr> def = 
std::make_shared<MDCPatternConverter>();
-               return def;
-       }
+               return std::make_shared<MDCPatternConverter>();
        return std::make_shared<MDCPatternConverter>(LogString(), 
options.front());
 }
 
@@ -52,24 +49,39 @@ void MDCPatternConverter::format
        ) const
 {
        size_t startIndex = toAppendTo.size();
+       auto& info = getFormattingInfo();
        if (m_priv->name.empty()) // Full MDC required?
        {
-               bool first = true;
+               const size_t separCount = 2;
+               const size_t quoteCount = 2;
+               LogString separ = LOG4CXX_STR("{");
+               size_t remainingLength = info.getMaxLength() - 1;
                for (auto key : event->getMDCKeySet())
                {
-                       toAppendTo.append(first ? LOG4CXX_STR("{") : 
LOG4CXX_STR(","));
-                       JSONLayout::appendItem(key, toAppendTo);
-                       toAppendTo.append(LOG4CXX_STR(":"));
                        LogString value;
                        event->getMDC(key, value);
+                       auto itemLength = separCount + key.length() + 
quoteCount + value.length() + quoteCount;
+                       if (remainingLength < itemLength)
+                               break;
+                       toAppendTo.append(separ);
+                       JSONLayout::appendItem(key, toAppendTo);
+                       toAppendTo.append(LOG4CXX_STR(":"));
                        JSONLayout::appendItem(value, toAppendTo);
-                       first = false;
+                       separ = LOG4CXX_STR(",");
+                       remainingLength -= itemLength;
                }
-               if (!first)
+               if (LOG4CXX_STR(",") == separ)
                        toAppendTo.append(LOG4CXX_STR("}"));
        }
        else
-               event->getMDC(m_priv->name, toAppendTo);
+       {
+               LogString value;
+               event->getMDC(m_priv->name, value);
+               if (info.getMaxLength() < value.length())
+                       toAppendTo.append(value.substr(value.length() - 
info.getMaxLength()));
+               else
+                       toAppendTo.append(value);
+       }
        if (!m_priv->style.empty()) // In a quoted context?
        {
                auto quote = m_priv->style.front();
diff --git a/src/main/cpp/messagepatternconverter.cpp 
b/src/main/cpp/messagepatternconverter.cpp
index 6b0712ff..f31ba448 100644
--- a/src/main/cpp/messagepatternconverter.cpp
+++ b/src/main/cpp/messagepatternconverter.cpp
@@ -72,8 +72,7 @@ PatternConverterPtr MessagePatternConverter::newInstance(
 {
        if (options.empty() || options.front().empty())
        {
-               static helpers::WideLife<PatternConverterPtr> def = 
std::make_shared<MessagePatternConverter>();
-               return def;
+               return std::make_shared<MessagePatternConverter>();
        }
        return 
std::make_shared<QuotedMessagePatternConverter>(options.front().front());
 }
@@ -84,6 +83,11 @@ void MessagePatternConverter::format
        , helpers::Pool&           /* p */
        ) const
 {
-       toAppendTo.append(event->getRenderedMessage());
+       auto& msg = event->getRenderedMessage();
+       auto& info = getFormattingInfo();
+       if (info.getMaxLength() < msg.length())
+               toAppendTo.append(&msg[msg.length() - info.getMaxLength()], 
info.getMaxLength());
+       else
+               toAppendTo.append(msg);
 }
 
diff --git a/src/main/cpp/methodlocationpatternconverter.cpp 
b/src/main/cpp/methodlocationpatternconverter.cpp
index 2e479c8b..db0cb7aa 100644
--- a/src/main/cpp/methodlocationpatternconverter.cpp
+++ b/src/main/cpp/methodlocationpatternconverter.cpp
@@ -36,8 +36,7 @@ 
MethodLocationPatternConverter::MethodLocationPatternConverter() :
 PatternConverterPtr MethodLocationPatternConverter::newInstance(
        const std::vector<LogString>& /* options */ )
 {
-       static WideLife<PatternConverterPtr> def = 
std::make_shared<MethodLocationPatternConverter>();
-       return def;
+       return std::make_shared<MethodLocationPatternConverter>();
 }
 
 void MethodLocationPatternConverter::format(
diff --git a/src/main/cpp/ndcpatternconverter.cpp 
b/src/main/cpp/ndcpatternconverter.cpp
index 6b05759c..c8a6b500 100644
--- a/src/main/cpp/ndcpatternconverter.cpp
+++ b/src/main/cpp/ndcpatternconverter.cpp
@@ -36,8 +36,7 @@ NDCPatternConverter::NDCPatternConverter() :
 PatternConverterPtr NDCPatternConverter::newInstance(
        const std::vector<LogString>& /* options */)
 {
-       static WideLife<PatternConverterPtr> def = 
std::make_shared<NDCPatternConverter>();
-       return def;
+       return std::make_shared<NDCPatternConverter>();
 }
 
 void NDCPatternConverter::format(
@@ -45,7 +44,16 @@ void NDCPatternConverter::format(
        LogString& toAppendTo,
        Pool& /* p */) const
 {
-       if (!event->getNDC(toAppendTo))
+       LogString value;
+       if (event->getNDC(value))
+       {
+               auto& info = getFormattingInfo();
+               if (info.getMaxLength() < value.length())
+                       toAppendTo.append(value.substr(value.length() - 
info.getMaxLength()));
+               else
+                       toAppendTo.append(value);
+       }
+       else
        {
                toAppendTo.append(LOG4CXX_STR("null"));
        }
diff --git a/src/main/cpp/patternconverter.cpp 
b/src/main/cpp/patternconverter.cpp
index 5fe92c3e..c1120da0 100644
--- a/src/main/cpp/patternconverter.cpp
+++ b/src/main/cpp/patternconverter.cpp
@@ -58,3 +58,12 @@ void PatternConverter::append(LogString& toAppendTo, const 
std::string& src)
        toAppendTo.append(decoded);
 }
 
+const FormattingInfo& PatternConverter::getFormattingInfo() const
+{
+       return *m_priv->info;
+}
+
+void PatternConverter::setFormattingInfo(const FormattingInfoPtr& newValue)
+{
+       m_priv->info = newValue;
+}
diff --git a/src/main/cpp/patternlayout.cpp b/src/main/cpp/patternlayout.cpp
index 68d43c5e..6a29183d 100644
--- a/src/main/cpp/patternlayout.cpp
+++ b/src/main/cpp/patternlayout.cpp
@@ -75,11 +75,6 @@ struct PatternLayout::PatternLayoutPrivate
         */
        LoggingEventPatternConverterList patternConverters;
 
-       /**
-        * Field widths and alignment corresponding to pattern converters.
-        */
-       FormattingInfoList patternFields;
-
        LogString m_fatalColor = LOG4CXX_STR("\\x1B[35m"); //magenta
        LogString m_errorColor = LOG4CXX_STR("\\x1B[31m"); //red
        LogString m_warnColor = LOG4CXX_STR("\\x1B[33m"); //yellow
@@ -124,17 +119,13 @@ void PatternLayout::format(LogString& output,
 {
        auto& lsMsg = event->getRenderedMessage();
        output.reserve(m_priv->expectedPatternLength + lsMsg.size());
-       std::vector<FormattingInfoPtr>::const_iterator formatterIter =
-               m_priv->patternFields.begin();
 
-       for (std::vector<LoggingEventPatternConverterPtr>::const_iterator
-               converterIter = m_priv->patternConverters.begin();
-               converterIter != m_priv->patternConverters.end();
-               converterIter++, formatterIter++)
+       for (auto item : m_priv->patternConverters)
        {
-               int startField = (int)output.length();
-               (*converterIter)->format(event, output, pool);
-               (*formatterIter)->format(startField, output);
+               auto startField = output.length();
+               item->format(event, output, pool);
+               if (startField < INT_MAX)
+                       
item->getFormattingInfo().format(static_cast<int>(startField), output);
        }
 
 }
@@ -189,12 +180,7 @@ void PatternLayout::activateOptions(Pool&)
        }
 
        m_priv->patternConverters.erase(m_priv->patternConverters.begin(), 
m_priv->patternConverters.end());
-       m_priv->patternFields.erase(m_priv->patternFields.begin(), 
m_priv->patternFields.end());
-       std::vector<PatternConverterPtr> converters;
-       PatternParser::parse(pat,
-               converters,
-               m_priv->patternFields,
-               getFormatSpecifiers());
+       auto converters = PatternParser::parse(pat, getFormatSpecifiers());
 
        //
        //   strip out any pattern converters that don't handle LoggingEvents
diff --git a/src/main/cpp/patternparser.cpp b/src/main/cpp/patternparser.cpp
index d27ba07e..ded7a37d 100644
--- a/src/main/cpp/patternparser.cpp
+++ b/src/main/cpp/patternparser.cpp
@@ -112,13 +112,23 @@ size_t PatternParser::extractOptions(const LogString& 
pattern, LogString::size_t
        return i;
 }
 
+#if LOG4CXX_ABI_VERSION <= 15
 void PatternParser::parse(
        const LogString& pattern,
        std::vector<PatternConverterPtr>& patternConverters,
        std::vector<FormattingInfoPtr>& formattingInfos,
        const PatternMap& rules)
 {
+       patternConverters = parse(pattern, rules);
+}
+#endif
 
+PatternConverterList PatternParser::parse
+       ( const LogString&      pattern
+       , const PatternMap&     rules
+       )
+{
+       PatternConverterList patternConverters;
        LogString currentLiteral;
 
        size_t patternLength = pattern.length();
@@ -126,7 +136,7 @@ void PatternParser::parse(
        logchar c;
        size_t i = 0;
        int minDigitCount{ 0 }, maxDigitCount{ 0 };
-       FormattingInfoPtr formattingInfo(FormattingInfo::getDefault());
+       auto formattingInfo = FormattingInfo::getDefault();
 
        while (i < patternLength)
        {
@@ -158,7 +168,6 @@ void PatternParser::parse(
                                                {
                                                        
patternConverters.push_back(
                                                                
LiteralPatternConverter::newInstance(currentLiteral));
-                                                       
formattingInfos.push_back(FormattingInfo::getDefault());
                                                        
currentLiteral.erase(currentLiteral.begin(), currentLiteral.end());
                                                }
 
@@ -205,7 +214,7 @@ void PatternParser::parse(
                                                {
                                                        i = finalizeConverter(
                                                                        c, 
pattern, i, currentLiteral, formattingInfo,
-                                                                       rules, 
patternConverters, formattingInfos);
+                                                                       rules, 
patternConverters);
 
                                                        // Next pattern is 
assumed to be a literal.
                                                        state = LITERAL_STATE;
@@ -239,7 +248,7 @@ void PatternParser::parse(
                                {
                                        i = finalizeConverter(
                                                        c, pattern, i, 
currentLiteral, formattingInfo,
-                                                       rules, 
patternConverters, formattingInfos);
+                                                       rules, 
patternConverters);
                                        state = LITERAL_STATE;
                                        formattingInfo = 
FormattingInfo::getDefault();
 
@@ -285,7 +294,7 @@ void PatternParser::parse(
                                {
                                        i = finalizeConverter(
                                                        c, pattern, i, 
currentLiteral, formattingInfo,
-                                                       rules, 
patternConverters, formattingInfos);
+                                                       rules, 
patternConverters);
                                        state = LITERAL_STATE;
                                        formattingInfo = 
FormattingInfo::getDefault();
 
@@ -304,8 +313,8 @@ void PatternParser::parse(
        {
                patternConverters.push_back(
                        LiteralPatternConverter::newInstance(currentLiteral));
-               formattingInfos.push_back(FormattingInfo::getDefault());
        }
+       return patternConverters;
 }
 
 
@@ -340,8 +349,7 @@ size_t PatternParser::finalizeConverter(
        logchar c, const LogString& pattern, size_t i,
        LogString& currentLiteral, const FormattingInfoPtr& formattingInfo,
        const PatternMap&  rules,
-       std::vector<PatternConverterPtr>& patternConverters,
-       std::vector<FormattingInfoPtr>&  formattingInfos)
+       PatternConverterList& patternConverters)
 {
        LogString convBuf;
        i = extractConverter(c, pattern, i, convBuf, currentLiteral);
@@ -351,7 +359,6 @@ size_t PatternParser::finalizeConverter(
                LogLog::error(LOG4CXX_STR("Empty conversion specifier"));
                patternConverters.push_back(
                        LiteralPatternConverter::newInstance(currentLiteral));
-               formattingInfos.push_back(FormattingInfo::getDefault());
        }
        else
        {
@@ -372,18 +379,16 @@ size_t PatternParser::finalizeConverter(
                        LogLog::error(msg);
                        patternConverters.push_back(
                                
LiteralPatternConverter::newInstance(currentLiteral));
-                       formattingInfos.push_back(FormattingInfo::getDefault());
                }
                else
                {
                        patternConverters.push_back(pc);
-                       formattingInfos.push_back(formattingInfo);
+                       pc->setFormattingInfo(formattingInfo);
 
                        if (currentLiteral.length() > 0)
                        {
                                patternConverters.push_back(
                                        
LiteralPatternConverter::newInstance(currentLiteral));
-                               
formattingInfos.push_back(FormattingInfo::getDefault());
                        }
                }
        }
diff --git a/src/main/cpp/propertiespatternconverter.cpp 
b/src/main/cpp/propertiespatternconverter.cpp
index ef9c3521..46b148bc 100644
--- a/src/main/cpp/propertiespatternconverter.cpp
+++ b/src/main/cpp/propertiespatternconverter.cpp
@@ -56,9 +56,8 @@ PatternConverterPtr PropertiesPatternConverter::newInstance(
 {
        if (options.size() == 0)
        {
-               static WideLife<PatternConverterPtr> def = 
std::make_shared<PropertiesPatternConverter>(
+               return std::make_shared<PropertiesPatternConverter>(
                                LOG4CXX_STR("Properties"), LOG4CXX_STR(""));
-               return def;
        }
 
        LogString converterName(LOG4CXX_STR("Property{"));
diff --git a/src/main/cpp/rollingpolicybase.cpp 
b/src/main/cpp/rollingpolicybase.cpp
index e6630412..a4560753 100644
--- a/src/main/cpp/rollingpolicybase.cpp
+++ b/src/main/cpp/rollingpolicybase.cpp
@@ -95,12 +95,7 @@ LogString RollingPolicyBase::getFileNamePattern() const
  */
 void RollingPolicyBase::parseFileNamePattern()
 {
-       m_priv->patternConverters.erase(m_priv->patternConverters.begin(), 
m_priv->patternConverters.end());
-       m_priv->patternFields.erase(m_priv->patternFields.begin(), 
m_priv->patternFields.end());
-       PatternParser::parse(m_priv->fileNamePatternStr,
-               m_priv->patternConverters,
-               m_priv->patternFields,
-               getFormatSpecifiers());
+       m_priv->patternConverters = 
PatternParser::parse(m_priv->fileNamePatternStr, getFormatSpecifiers());
 }
 
 /**
@@ -114,17 +109,11 @@ void RollingPolicyBase::formatFileName(
        LogString& toAppendTo,
        Pool& pool) const
 {
-       std::vector<FormattingInfoPtr>::const_iterator formatterIter =
-               m_priv->patternFields.begin();
-
-       for (std::vector<PatternConverterPtr>::const_iterator
-               converterIter = m_priv->patternConverters.begin();
-               converterIter != m_priv->patternConverters.end();
-               converterIter++, formatterIter++)
+       for (auto item : m_priv->patternConverters)
        {
                auto startField = toAppendTo.length();
-               (*converterIter)->format(obj, toAppendTo, pool);
-               (*formatterIter)->format((int)startField, toAppendTo);
+               item->format(obj, toAppendTo, pool);
+               item->getFormattingInfo().format((int)startField, toAppendTo);
        }
 }
 
diff --git a/src/main/cpp/shortfilelocationpatternconverter.cpp 
b/src/main/cpp/shortfilelocationpatternconverter.cpp
index 0bd2ed88..f4f7d7b3 100644
--- a/src/main/cpp/shortfilelocationpatternconverter.cpp
+++ b/src/main/cpp/shortfilelocationpatternconverter.cpp
@@ -34,8 +34,7 @@ 
ShortFileLocationPatternConverter::ShortFileLocationPatternConverter() :
 
 PatternConverterPtr ShortFileLocationPatternConverter::newInstance(
     const std::vector<LogString> & /* options */ ) {
-  static WideLife<PatternConverterPtr> instance(new 
ShortFileLocationPatternConverter());
-  return instance;
+  return PatternConverterPtr(new ShortFileLocationPatternConverter());
 }
 
 void ShortFileLocationPatternConverter::format(
diff --git a/src/main/cpp/threadpatternconverter.cpp 
b/src/main/cpp/threadpatternconverter.cpp
index 18c054df..9464502a 100644
--- a/src/main/cpp/threadpatternconverter.cpp
+++ b/src/main/cpp/threadpatternconverter.cpp
@@ -36,8 +36,7 @@ ThreadPatternConverter::ThreadPatternConverter() :
 PatternConverterPtr ThreadPatternConverter::newInstance(
        const std::vector<LogString>& /* options */)
 {
-       static WideLife<PatternConverterPtr> def = 
std::make_shared<ThreadPatternConverter>();
-       return def;
+       return std::make_shared<ThreadPatternConverter>();
 }
 
 void ThreadPatternConverter::format(
diff --git a/src/main/cpp/threadusernamepatternconverter.cpp 
b/src/main/cpp/threadusernamepatternconverter.cpp
index 621393b1..40794e7c 100644
--- a/src/main/cpp/threadusernamepatternconverter.cpp
+++ b/src/main/cpp/threadusernamepatternconverter.cpp
@@ -36,8 +36,7 @@ 
ThreadUsernamePatternConverter::ThreadUsernamePatternConverter() :
 PatternConverterPtr ThreadUsernamePatternConverter::newInstance(
        const std::vector<LogString>& /* options */)
 {
-       static WideLife<PatternConverterPtr> def = 
std::make_shared<ThreadUsernamePatternConverter>();
-       return def;
+       return std::make_shared<ThreadUsernamePatternConverter>();
 }
 
 void ThreadUsernamePatternConverter::format(
diff --git a/src/main/cpp/throwableinformationpatternconverter.cpp 
b/src/main/cpp/throwableinformationpatternconverter.cpp
index 45e4fafe..d03d3b29 100644
--- a/src/main/cpp/throwableinformationpatternconverter.cpp
+++ b/src/main/cpp/throwableinformationpatternconverter.cpp
@@ -56,12 +56,10 @@ PatternConverterPtr 
ThrowableInformationPatternConverter::newInstance(
 {
        if (options.size() > 0 && options[0].compare(LOG4CXX_STR("short")) == 0)
        {
-               static WideLife<PatternConverterPtr> shortConverter = 
std::make_shared<ThrowableInformationPatternConverter>(true);
-               return shortConverter;
+               return 
std::make_shared<ThrowableInformationPatternConverter>(true);
        }
 
-       static WideLife<PatternConverterPtr> converter = 
std::make_shared<ThrowableInformationPatternConverter>(false);
-       return converter;
+       return std::make_shared<ThrowableInformationPatternConverter>(false);
 }
 
 void ThrowableInformationPatternConverter::format(
diff --git a/src/main/include/log4cxx/pattern/patternconverter.h 
b/src/main/include/log4cxx/pattern/patternconverter.h
index 9bcf8c84..8e4852e5 100644
--- a/src/main/include/log4cxx/pattern/patternconverter.h
+++ b/src/main/include/log4cxx/pattern/patternconverter.h
@@ -21,6 +21,7 @@
 
 #include <log4cxx/helpers/object.h>
 #include <log4cxx/logstring.h>
+#include <log4cxx/pattern/formattinginfo.h>
 #include <vector>
 
 #define DECLARE_LOG4CXX_PATTERN(cls) DECLARE_ABSTRACT_LOG4CXX_OBJECT(cls)
@@ -95,6 +96,16 @@ class LOG4CXX_EXPORT PatternConverter : public virtual 
helpers::Object
                 */
                virtual LogString getStyleClass(const helpers::ObjectPtr& e) 
const;
 
+        /**
+         * Provides a minimum width, a maximum width and the alignment
+         */
+        const FormattingInfo& getFormattingInfo() const;
+
+        /**
+         * Use \c newValue for the minimum width, a maximum width and the 
alignment
+         */
+        void setFormattingInfo(const FormattingInfoPtr& newValue);
+
        protected:
                /**
                * Appends content in the locale code page to a LogString.
diff --git a/src/main/include/log4cxx/pattern/patternparser.h 
b/src/main/include/log4cxx/pattern/patternparser.h
index 0cc6ba6e..5b2f39cc 100644
--- a/src/main/include/log4cxx/pattern/patternparser.h
+++ b/src/main/include/log4cxx/pattern/patternparser.h
@@ -33,7 +33,7 @@ namespace pattern
 
 typedef std::function<PatternConverterPtr(const std::vector<LogString>& 
options)> PatternConstructor;
 typedef std::map<LogString, PatternConstructor> PatternMap;
-
+LOG4CXX_LIST_DEF(PatternConverterList, PatternConverterPtr);
 
 // Contributors:   Nelson Minar <([email protected]>
 //                 Igor E. Poteryaev <[email protected]>
@@ -100,18 +100,31 @@ class LOG4CXX_EXPORT PatternParser
                        std::vector<LogString>& options);
 
        public:
+#if LOG4CXX_ABI_VERSION <= 15
                /**
                 * Parse a format specifier.
+                * @deprecated This function is deprecated and will be removed 
in a future version.
                 * @param pattern pattern to parse.
                 * @param patternConverters list to receive pattern converters.
                 * @param formattingInfos list to receive field specifiers 
corresponding to pattern converters.
                 * @param rules map of stock pattern converters keyed by format 
specifier.
                 */
+               [[ deprecated( "Parsing into two vectors is longer supported" ) 
]]
                static void parse(
                        const LogString& pattern,
                        std::vector<PatternConverterPtr>& patternConverters,
                        std::vector<FormattingInfoPtr>& formattingInfos,
                        const PatternMap& rules);
+#endif
+               /**
+                * Convert \c pattern to converters using \c rules.
+                * @param pattern a string specifying the conversion types and 
their properties.
+                * @param rules a map of stock pattern converters keyed by name.
+                */
+               static PatternConverterList parse
+                       ( const LogString&      pattern
+                       , const PatternMap&     rules
+                       );
 
        private:
                /**
@@ -148,8 +161,8 @@ class LOG4CXX_EXPORT PatternParser
                        logchar c, const LogString& pattern, size_t i,
                        LogString& currentLiteral, const FormattingInfoPtr& 
formattingInfo,
                        const PatternMap&  rules,
-                       std::vector<PatternConverterPtr>& patternConverters,
-                       std::vector<FormattingInfoPtr>&  formattingInfos);
+                       PatternConverterList& patternConverter
+                       );
 
                static bool isUnicodeIdentifierStart(logchar c);
                static bool isUnicodeIdentifierPart(logchar c);
diff --git a/src/main/include/log4cxx/private/patternconverter_priv.h 
b/src/main/include/log4cxx/private/patternconverter_priv.h
index 0027ad5a..9e7b8aeb 100644
--- a/src/main/include/log4cxx/private/patternconverter_priv.h
+++ b/src/main/include/log4cxx/private/patternconverter_priv.h
@@ -17,6 +17,7 @@
 #ifndef LOG4CXX_PATTERNCONVERTER_PRIVATE_H
 #define LOG4CXX_PATTERNCONVERTER_PRIVATE_H
 #include <log4cxx/pattern/patternconverter.h>
+#include <log4cxx/pattern/formattinginfo.h>
 
 namespace LOG4CXX_NS
 {
@@ -44,6 +45,11 @@ struct PatternConverter::PatternConverterPrivate
         * Converter style name.
         */
        const LogString style;
+
+    /**
+     * Provides field size limits
+     */
+    FormattingInfoPtr info{ FormattingInfo::getDefault() };
 };
 
 }
diff --git a/src/main/include/log4cxx/private/rollingpolicybase_priv.h 
b/src/main/include/log4cxx/private/rollingpolicybase_priv.h
index 829bb036..467fa448 100644
--- a/src/main/include/log4cxx/private/rollingpolicybase_priv.h
+++ b/src/main/include/log4cxx/private/rollingpolicybase_priv.h
@@ -35,11 +35,6 @@ struct RollingPolicyBase::RollingPolicyBasePrivate {
      */
     PatternConverterList patternConverters;
 
-    /**
-     * File name field specifiers.
-     */
-    FormattingInfoList patternFields;
-
     /**
      * File name pattern.
      */
diff --git a/src/main/include/log4cxx/rolling/rollingpolicybase.h 
b/src/main/include/log4cxx/rolling/rollingpolicybase.h
index 9399286f..e2f85534 100644
--- a/src/main/include/log4cxx/rolling/rollingpolicybase.h
+++ b/src/main/include/log4cxx/rolling/rollingpolicybase.h
@@ -31,7 +31,6 @@ namespace LOG4CXX_NS
 namespace rolling
 {
 LOG4CXX_LIST_DEF(PatternConverterList, 
LOG4CXX_NS::pattern::PatternConverterPtr);
-LOG4CXX_LIST_DEF(FormattingInfoList, LOG4CXX_NS::pattern::FormattingInfoPtr);
 
 /**
  * Implements methods common to most, it not all, rolling
diff --git a/src/test/cpp/mdctestcase.cpp b/src/test/cpp/mdctestcase.cpp
index 06f4f3ac..c17082bf 100644
--- a/src/test/cpp/mdctestcase.cpp
+++ b/src/test/cpp/mdctestcase.cpp
@@ -19,7 +19,7 @@
 #include <log4cxx/mdc.h>
 #include <log4cxx/file.h>
 #include <log4cxx/logger.h>
-#include <log4cxx/propertyconfigurator.h>
+#include <log4cxx/patternlayout.h>
 #include "insertwide.h"
 #include "logunit.h"
 #include "util/compare.h"
@@ -32,6 +32,7 @@ LOGUNIT_CLASS(MDCTestCase)
 {
        LOGUNIT_TEST_SUITE(MDCTestCase);
        LOGUNIT_TEST(test1);
+       LOGUNIT_TEST(test2);
        LOGUNIT_TEST_SUITE_END();
 
 public:
@@ -57,11 +58,23 @@ public:
        {
                std::string key("key1");
                std::string expected("value2");
-               MDC::put(key, "value1");
+               MDC item1(key, "value1");
                MDC::put(key, expected);
                std::string actual(MDC::get(key));
                LOGUNIT_ASSERT_EQUAL(expected, actual);
        }
+
+       /// Check MDC formatting skips entries that exceed the maximum field 
length.
+       void test2()
+       {
+               MDC item1("key1", "value1");
+               MDC item2("key2", "value2");
+               helpers::Pool p;
+               LogString output;
+               PatternLayout l{ LOG4CXX_STR("%-5p %c - %.30J %m") };
+               l.format(output, 
std::make_shared<spi::LoggingEvent>(LOG4CXX_STR("MDC.LayoutTest"), 
Level::getInfo(), LOG4CXX_STR("Message"), 
spi::LocationInfo::getLocationUnavailable()), p);
+               LOGUNIT_ASSERT_EQUAL(LOG4CXX_STR("INFO  MDC.LayoutTest - 
{\"key1\":\"value1\"} Message"), output);
+       }
 };
 
 LOGUNIT_TEST_SUITE_REGISTRATION(MDCTestCase);
diff --git a/src/test/cpp/ndctestcase.cpp b/src/test/cpp/ndctestcase.cpp
index 383f7a71..0d3112c8 100644
--- a/src/test/cpp/ndctestcase.cpp
+++ b/src/test/cpp/ndctestcase.cpp
@@ -20,6 +20,7 @@
 #include <log4cxx/file.h>
 #include <log4cxx/logger.h>
 #include <log4cxx/propertyconfigurator.h>
+#include <log4cxx/patternlayout.h>
 #include "insertwide.h"
 #include "logunit.h"
 #include "util/compare.h"
@@ -37,6 +38,7 @@ LOGUNIT_CLASS(NDCTestCase)
        LOGUNIT_TEST(testPushPop);
        LOGUNIT_TEST(test1);
        LOGUNIT_TEST(testInherit);
+       LOGUNIT_TEST(testFieldPrecision);
        LOGUNIT_TEST_SUITE_END();
 
 public:
@@ -113,6 +115,19 @@ public:
                LOGUNIT_ASSERT_EQUAL(expected3, NDC::pop());
        }
 
+       /// Check NDC formatting uses to suffix when the maximum field length 
is exceeded.
+       void testFieldPrecision()
+       {
+               NDC item1("context1");
+               NDC item2("context2");
+               NDC item3("context3");
+               helpers::Pool p;
+               LogString output;
+               PatternLayout l{ LOG4CXX_STR("%-5p %c - %.20x %m") };
+               l.format(output, 
std::make_shared<spi::LoggingEvent>(LOG4CXX_STR("NDC.LayoutTest"), 
Level::getInfo(), LOG4CXX_STR("Message"), 
spi::LocationInfo::getLocationUnavailable()), p);
+               LOGUNIT_ASSERT_EQUAL(LOG4CXX_STR("INFO  NDC.LayoutTest - t1 
context2 context3 Message"), output);
+       }
+
 };
 
 
diff --git a/src/test/cpp/pattern/patternparsertestcase.cpp 
b/src/test/cpp/pattern/patternparsertestcase.cpp
index 4a4d88c7..2c030198 100644
--- a/src/test/cpp/pattern/patternparsertestcase.cpp
+++ b/src/test/cpp/pattern/patternparsertestcase.cpp
@@ -170,20 +170,15 @@ public:
                const PatternMap & patternMap,
                const LogString & expected)
        {
-               std::vector<PatternConverterPtr> converters;
-               std::vector<FormattingInfoPtr> fields;
-               PatternParser::parse(pattern, converters, fields, patternMap);
+               auto converters = PatternParser::parse(pattern, patternMap);
                Pool p;
                LogString actual;
-               std::vector<FormattingInfoPtr>::const_iterator fieldIter = 
fields.begin();
 
-               for (std::vector<PatternConverterPtr>::const_iterator 
converterIter = converters.begin();
-                       converterIter != converters.end();
-                       converterIter++, fieldIter++)
+               for (auto item : converters)
                {
                        auto fieldStart = static_cast<int>(actual.length());
-                       (*converterIter)->format(event, actual, p);
-                       (*fieldIter)->format(fieldStart, actual);
+                       item->format(event, actual, p);
+                       item->getFormattingInfo().format(fieldStart, actual);
                }
 
                LOGUNIT_ASSERT_EQUAL(expected, actual);
diff --git a/src/test/cpp/patternlayouttest.cpp 
b/src/test/cpp/patternlayouttest.cpp
index c142ae04..6301519f 100644
--- a/src/test/cpp/patternlayouttest.cpp
+++ b/src/test/cpp/patternlayouttest.cpp
@@ -63,6 +63,7 @@ using namespace log4cxx::helpers;
 LOGUNIT_CLASS(PatternLayoutTest)
 {
        LOGUNIT_TEST_SUITE(PatternLayoutTest);
+       LOGUNIT_TEST(test2GbMessageFormatting);
        LOGUNIT_TEST(test1);
        LOGUNIT_TEST(test2);
        LOGUNIT_TEST(test3);
@@ -103,6 +104,22 @@ public:
                }
        }
 
+       void test2GbMessageFormatting()
+       {
+               LogString msg(size_t(INT_MAX) + 1000, 'E');
+               msg[msg.length() - 1] = 'X';
+               Pool p;
+               LogString output1;
+               PatternLayout l1{ LOG4CXX_STR("%-5p %c{2} - %.30m") };
+               l1.format(output1, 
std::make_shared<spi::LoggingEvent>(logger->getName(), Level::getInfo(), msg, 
spi::LocationInfo::getLocationUnavailable()), p);
+               LOGUNIT_ASSERT_EQUAL(LOG4CXX_STR("INFO  log4j.PatternLayoutTest 
- EEEEEEEEEEEEEEEEEEEEEEEEEEEEEX"), output1);
+
+               PatternLayout l2{ LOG4CXX_STR("%p %.30m %p") };
+               LogString output2;
+               l2.format(output2, 
std::make_shared<spi::LoggingEvent>(logger->getName(), Level::getDebug(), msg, 
spi::LocationInfo::getLocationUnavailable()), p);
+               LOGUNIT_ASSERT_EQUAL(LOG4CXX_STR("DEBUG 
EEEEEEEEEEEEEEEEEEEEEEEEEEEEEX DEBUG"), output2);
+       }
+
        void test1()
        {
                auto status = 
PropertyConfigurator::configure(LOG4CXX_FILE("input/patternLayout1.properties"));
diff --git a/src/test/cpp/rolling/filenamepatterntestcase.cpp 
b/src/test/cpp/rolling/filenamepatterntestcase.cpp
index eb29cbba..01a834fa 100644
--- a/src/test/cpp/rolling/filenamepatterntestcase.cpp
+++ b/src/test/cpp/rolling/filenamepatterntestcase.cpp
@@ -66,23 +66,18 @@ public:
        LogString format(const LogString & pattern,
                const ObjectPtr & obj)
        {
-               std::vector<PatternConverterPtr> converters;
-               std::vector<FormattingInfoPtr> fields;
                PatternMap rules;
                rules.insert(PatternMap::value_type(LOG4CXX_STR("d"), 
(PatternConstructor) FileDatePatternConverter::newInstance));
                rules.insert(PatternMap::value_type(LOG4CXX_STR("i"), 
(PatternConstructor) IntegerPatternConverter::newInstance));
-               PatternParser::parse(pattern, converters, fields, rules);
+               auto converters = PatternParser::parse(pattern, rules);
                LogString result;
                Pool pool;
-               std::vector<FormattingInfoPtr>::const_iterator fieldIter = 
fields.begin();
 
-               for (std::vector<PatternConverterPtr>::const_iterator 
converterIter = converters.begin();
-                       converterIter != converters.end();
-                       converterIter++, fieldIter++)
+               for (auto item :  converters)
                {
                        LogString::size_type i = result.length();
-                       (*converterIter)->format(obj, result, pool);
-                       (*fieldIter)->format(i, result);
+                       item->format(obj, result, pool);
+                       item->getFormattingInfo().format((int)i, result);
                }
 
                return result;


Reply via email to