Coverage Report

Created: 2026-08-31 06:56

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/logging-log4cxx/src/main/cpp/mdcpatternconverter.cpp
Line
Count
Source
1
/*
2
 * Licensed to the Apache Software Foundation (ASF) under one or more
3
 * contributor license agreements.  See the NOTICE file distributed with
4
 * this work for additional information regarding copyright ownership.
5
 * The ASF licenses this file to You under the Apache License, Version 2.0
6
 * (the "License"); you may not use this file except in compliance with
7
 * the License.  You may obtain a copy of the License at
8
 *
9
 *      http://www.apache.org/licenses/LICENSE-2.0
10
 *
11
 * Unless required by applicable law or agreed to in writing, software
12
 * distributed under the License is distributed on an "AS IS" BASIS,
13
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
 * See the License for the specific language governing permissions and
15
 * limitations under the License.
16
 */
17
18
#include <log4cxx/pattern/mdcpatternconverter.h>
19
#include <log4cxx/private/patternconverter_priv.h>
20
#include <log4cxx/spi/loggingevent.h>
21
#include <log4cxx/jsonlayout.h>
22
23
using namespace LOG4CXX_NS;
24
using namespace LOG4CXX_NS::pattern;
25
26
IMPLEMENT_LOG4CXX_OBJECT(MDCPatternConverter)
27
28
MDCPatternConverter::MDCPatternConverter
29
  ( const LogString&              name
30
  , const LogString&              style
31
  , const std::vector<LogString>& options
32
  )
33
0
  : LoggingEventPatternConverter(std::make_unique<PatternConverter::PatternConverterPrivate>(name, style))
34
0
{
35
0
}
Unexecuted instantiation: log4cxx::pattern::MDCPatternConverter::MDCPatternConverter(std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&, std::__1::vector<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, std::__1::allocator<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > > > const&)
Unexecuted instantiation: log4cxx::pattern::MDCPatternConverter::MDCPatternConverter(std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&, std::__1::vector<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, std::__1::allocator<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > > > const&)
36
37
PatternConverterPtr MDCPatternConverter::newInstance(
38
  const std::vector<LogString>& options)
39
0
{
40
0
  if (options.empty())
41
0
    return std::make_shared<MDCPatternConverter>();
42
0
  return std::make_shared<MDCPatternConverter>(LogString(), options.front());
43
0
}
44
45
void MDCPatternConverter::format( LOG4CXX_FORMAT_EVENT_FORMAL_PARAMETERS ) const
46
0
{
47
0
  size_t startIndex = toAppendTo.size();
48
0
  auto& info = getFormattingInfo();
49
0
  if (m_priv->name.empty()) // Full MDC required?
50
0
  {
51
0
    const size_t separCount = 2;
52
0
    const size_t quoteCount = 2;
53
0
    LogString separ = LOG4CXX_STR("{");
54
0
    size_t remainingLength = info.getMaxLength() > 0
55
0
      ? static_cast<size_t>(info.getMaxLength()) - 1
56
0
      : 0;
57
0
    for (auto key : event->getMDCKeySet())
58
0
    {
59
0
      LogString value;
60
0
      event->getMDC(key, value);
61
0
      auto itemLength = separCount + key.length() + quoteCount + value.length() + quoteCount;
62
0
      if (remainingLength < itemLength)
63
0
        break;
64
0
      toAppendTo.append(separ);
65
0
      JSONLayout::appendItem(key, toAppendTo);
66
0
      toAppendTo.append(LOG4CXX_STR(":"));
67
0
      JSONLayout::appendItem(value, toAppendTo);
68
0
      separ = LOG4CXX_STR(",");
69
0
      remainingLength -= itemLength;
70
0
    }
71
0
    if (LOG4CXX_STR(",") == separ)
72
0
      toAppendTo.append(LOG4CXX_STR("}"));
73
0
  }
74
0
  else
75
0
  {
76
0
    LogString value;
77
0
    event->getMDC(m_priv->name, value);
78
0
    if (info.getMaxLength() < value.length())
79
0
      toAppendTo.append(value.substr(value.length() - info.getMaxLength()));
80
0
    else
81
0
      toAppendTo.append(value);
82
0
  }
83
0
  if (!m_priv->style.empty()) // In a quoted context?
84
0
  {
85
0
    auto quote = m_priv->style.front();
86
0
    if (toAppendTo.find(quote, startIndex) != toAppendTo.npos)
87
0
    {
88
      // Duplicate each quote character in a single linear pass:
89
      // repeated single-character insert() shifts the tail of the
90
      // output buffer on every quote, which is quadratic in the
91
      // (attacker-controllable) MDC content length.
92
0
      LogString input = toAppendTo.substr(startIndex);
93
0
      toAppendTo.resize(startIndex);
94
0
      size_t endIndex, index = 0;
95
0
      while ((endIndex = input.find(quote, index)) != input.npos)
96
0
      {
97
0
        toAppendTo.append(input, index, endIndex - index + 1);
98
0
        toAppendTo += quote;
99
0
        index = endIndex + 1;
100
0
      }
101
0
      toAppendTo.append(input, index, LogString::npos);
102
0
    }
103
0
  }
104
0
}