Coverage Report

Created: 2025-10-12 06:49

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/brpc/src/butil/strings/stringprintf.cc
Line
Count
Source
1
// Copyright 2013 The Chromium Authors. All rights reserved.
2
// Use of this source code is governed by a BSD-style license that can be
3
// found in the LICENSE file.
4
5
#include "butil/strings/stringprintf.h"
6
7
#include <errno.h>
8
9
#include "butil/scoped_clear_errno.h"
10
#include "butil/strings/string_util.h"
11
#include "butil/strings/utf_string_conversions.h"
12
13
// gcc7 reports that the first arg to vsnprintfT in StringAppendVT is NULL,
14
// which I can't figure out why, turn off the warning right now.
15
#if defined(__GNUC__) && __GNUC__ >= 7
16
#pragma GCC diagnostic warning "-Wformat-truncation=0"
17
#endif
18
19
namespace butil {
20
21
namespace {
22
23
// Overloaded wrappers around vsnprintf and vswprintf. The buf_size parameter
24
// is the size of the buffer. These return the number of characters in the
25
// formatted string excluding the NUL terminator. If the buffer is not
26
// large enough to accommodate the formatted string without truncation, they
27
// return the number of characters that would be in the fully-formatted string
28
// (vsnprintf, and vswprintf on Windows), or -1 (vswprintf on POSIX platforms).
29
inline int vsnprintfT(char* buffer,
30
                      size_t buf_size,
31
                      const char* format,
32
0
                      va_list argptr) {
33
0
  return butil::vsnprintf(buffer, buf_size, format, argptr);
34
0
}
35
36
#if !defined(OS_ANDROID)
37
inline int vsnprintfT(wchar_t* buffer,
38
                      size_t buf_size,
39
                      const wchar_t* format,
40
0
                      va_list argptr) {
41
0
  return butil::vswprintf(buffer, buf_size, format, argptr);
42
0
}
43
#endif
44
45
// Templatized backend for StringPrintF/StringAppendF. This does not finalize
46
// the va_list, the caller is expected to do that.
47
template <class StringType>
48
static void StringAppendVT(StringType* dst,
49
                           const typename StringType::value_type* format,
50
0
                           va_list ap) {
51
  // First try with a small fixed size buffer.
52
  // This buffer size should be kept in sync with StringUtilTest.GrowBoundary
53
  // and StringUtilTest.StringPrintfBounds.
54
0
  typename StringType::value_type stack_buf[1024];
55
56
0
  va_list ap_copy;
57
0
  GG_VA_COPY(ap_copy, ap);
58
59
0
#if !defined(OS_WIN)
60
0
  ScopedClearErrno clear_errno;
61
0
#endif
62
0
  int result = vsnprintfT(stack_buf, arraysize(stack_buf), format, ap_copy);
63
0
  va_end(ap_copy);
64
65
0
  if (result >= 0 && result < static_cast<int>(arraysize(stack_buf))) {
66
    // It fit.
67
0
    dst->append(stack_buf, result);
68
0
    return;
69
0
  }
70
71
  // Repeatedly increase buffer size until it fits.
72
0
  int mem_length = arraysize(stack_buf);
73
0
  while (true) {
74
0
    if (result < 0) {
75
#if defined(OS_WIN)
76
      // On Windows, vsnprintfT always returns the number of characters in a
77
      // fully-formatted string, so if we reach this point, something else is
78
      // wrong and no amount of buffer-doubling is going to fix it.
79
      return;
80
#else
81
0
      if (errno != 0 && errno != EOVERFLOW)
82
0
        return;
83
      // Try doubling the buffer size.
84
0
      mem_length *= 2;
85
0
#endif
86
0
    } else {
87
      // We need exactly "result + 1" characters.
88
0
      mem_length = result + 1;
89
0
    }
90
91
0
    if (mem_length > 32 * 1024 * 1024) {
92
      // That should be plenty, don't try anything larger.  This protects
93
      // against huge allocations when using vsnprintfT implementations that
94
      // return -1 for reasons other than overflow without setting errno.
95
0
      DLOG(WARNING) << "Unable to printf the requested string due to size.";
96
0
      return;
97
0
    }
98
99
0
    std::vector<typename StringType::value_type> mem_buf(mem_length);
100
101
    // NOTE: You can only use a va_list once.  Since we're in a while loop, we
102
    // need to make a new copy each time so we don't use up the original.
103
0
    GG_VA_COPY(ap_copy, ap);
104
0
    result = vsnprintfT(&mem_buf[0], mem_length, format, ap_copy);
105
0
    va_end(ap_copy);
106
107
0
    if ((result >= 0) && (result < mem_length)) {
108
      // It fit.
109
0
      dst->append(&mem_buf[0], result);
110
0
      return;
111
0
    }
112
0
  }
113
0
}
Unexecuted instantiation: stringprintf.cc:void butil::(anonymous namespace)::StringAppendVT<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > >(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >*, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >::value_type const*, __va_list_tag*)
Unexecuted instantiation: stringprintf.cc:void butil::(anonymous namespace)::StringAppendVT<std::__cxx11::basic_string<wchar_t, std::char_traits<wchar_t>, std::allocator<wchar_t> > >(std::__cxx11::basic_string<wchar_t, std::char_traits<wchar_t>, std::allocator<wchar_t> >*, std::__cxx11::basic_string<wchar_t, std::char_traits<wchar_t>, std::allocator<wchar_t> >::value_type const*, __va_list_tag*)
114
115
}  // namespace
116
117
0
std::string StringPrintf(const char* format, ...) {
118
0
  va_list ap;
119
0
  va_start(ap, format);
120
0
  std::string result;
121
0
  StringAppendV(&result, format, ap);
122
0
  va_end(ap);
123
0
  return result;
124
0
}
125
126
#if !defined(OS_ANDROID)
127
0
std::wstring StringPrintf(const wchar_t* format, ...) {
128
0
  va_list ap;
129
0
  va_start(ap, format);
130
0
  std::wstring result;
131
0
  StringAppendV(&result, format, ap);
132
0
  va_end(ap);
133
0
  return result;
134
0
}
135
#endif
136
137
0
std::string StringPrintV(const char* format, va_list ap) {
138
0
  std::string result;
139
0
  StringAppendV(&result, format, ap);
140
0
  return result;
141
0
}
142
143
0
const std::string& SStringPrintf(std::string* dst, const char* format, ...) {
144
0
  va_list ap;
145
0
  va_start(ap, format);
146
0
  dst->clear();
147
0
  StringAppendV(dst, format, ap);
148
0
  va_end(ap);
149
0
  return *dst;
150
0
}
151
152
#if !defined(OS_ANDROID)
153
const std::wstring& SStringPrintf(std::wstring* dst,
154
0
                                  const wchar_t* format, ...) {
155
0
  va_list ap;
156
0
  va_start(ap, format);
157
0
  dst->clear();
158
0
  StringAppendV(dst, format, ap);
159
0
  va_end(ap);
160
0
  return *dst;
161
0
}
162
#endif
163
164
0
void StringAppendF(std::string* dst, const char* format, ...) {
165
0
  va_list ap;
166
0
  va_start(ap, format);
167
0
  StringAppendV(dst, format, ap);
168
0
  va_end(ap);
169
0
}
170
171
#if !defined(OS_ANDROID)
172
0
void StringAppendF(std::wstring* dst, const wchar_t* format, ...) {
173
0
  va_list ap;
174
0
  va_start(ap, format);
175
0
  StringAppendV(dst, format, ap);
176
0
  va_end(ap);
177
0
}
178
#endif
179
180
0
void StringAppendV(std::string* dst, const char* format, va_list ap) {
181
0
  StringAppendVT(dst, format, ap);
182
0
}
183
184
#if !defined(OS_ANDROID)
185
0
void StringAppendV(std::wstring* dst, const wchar_t* format, va_list ap) {
186
0
  StringAppendVT(dst, format, ap);
187
0
}
188
#endif
189
190
}  // namespace butil