1*6777b538SAndroid Build Coastguard Worker // Copyright 2013 The Chromium Authors
2*6777b538SAndroid Build Coastguard Worker // Use of this source code is governed by a BSD-style license that can be
3*6777b538SAndroid Build Coastguard Worker // found in the LICENSE file.
4*6777b538SAndroid Build Coastguard Worker
5*6777b538SAndroid Build Coastguard Worker #include "base/strings/stringprintf.h"
6*6777b538SAndroid Build Coastguard Worker
7*6777b538SAndroid Build Coastguard Worker #include <errno.h>
8*6777b538SAndroid Build Coastguard Worker #include <stddef.h>
9*6777b538SAndroid Build Coastguard Worker
10*6777b538SAndroid Build Coastguard Worker #include <vector>
11*6777b538SAndroid Build Coastguard Worker
12*6777b538SAndroid Build Coastguard Worker #include "base/logging.h"
13*6777b538SAndroid Build Coastguard Worker #include "base/scoped_clear_last_error.h"
14*6777b538SAndroid Build Coastguard Worker #include "base/strings/string_util.h"
15*6777b538SAndroid Build Coastguard Worker #include "build/build_config.h"
16*6777b538SAndroid Build Coastguard Worker
17*6777b538SAndroid Build Coastguard Worker namespace base {
18*6777b538SAndroid Build Coastguard Worker
StringPrintf(const char * format,...)19*6777b538SAndroid Build Coastguard Worker std::string StringPrintf(const char* format, ...) {
20*6777b538SAndroid Build Coastguard Worker va_list ap;
21*6777b538SAndroid Build Coastguard Worker va_start(ap, format);
22*6777b538SAndroid Build Coastguard Worker std::string result;
23*6777b538SAndroid Build Coastguard Worker StringAppendV(&result, format, ap);
24*6777b538SAndroid Build Coastguard Worker va_end(ap);
25*6777b538SAndroid Build Coastguard Worker return result;
26*6777b538SAndroid Build Coastguard Worker }
27*6777b538SAndroid Build Coastguard Worker
StringPrintV(const char * format,va_list ap)28*6777b538SAndroid Build Coastguard Worker std::string StringPrintV(const char* format, va_list ap) {
29*6777b538SAndroid Build Coastguard Worker std::string result;
30*6777b538SAndroid Build Coastguard Worker StringAppendV(&result, format, ap);
31*6777b538SAndroid Build Coastguard Worker return result;
32*6777b538SAndroid Build Coastguard Worker }
33*6777b538SAndroid Build Coastguard Worker
StringAppendF(std::string * dst,const char * format,...)34*6777b538SAndroid Build Coastguard Worker void StringAppendF(std::string* dst, const char* format, ...) {
35*6777b538SAndroid Build Coastguard Worker va_list ap;
36*6777b538SAndroid Build Coastguard Worker va_start(ap, format);
37*6777b538SAndroid Build Coastguard Worker StringAppendV(dst, format, ap);
38*6777b538SAndroid Build Coastguard Worker va_end(ap);
39*6777b538SAndroid Build Coastguard Worker }
40*6777b538SAndroid Build Coastguard Worker
StringAppendV(std::string * dst,const char * format,va_list ap)41*6777b538SAndroid Build Coastguard Worker void StringAppendV(std::string* dst, const char* format, va_list ap) {
42*6777b538SAndroid Build Coastguard Worker // First try with a small fixed size buffer.
43*6777b538SAndroid Build Coastguard Worker // This buffer size should be kept in sync with StringUtilTest.GrowBoundary
44*6777b538SAndroid Build Coastguard Worker // and StringUtilTest.StringPrintfBounds.
45*6777b538SAndroid Build Coastguard Worker char stack_buf[1024];
46*6777b538SAndroid Build Coastguard Worker
47*6777b538SAndroid Build Coastguard Worker va_list ap_copy;
48*6777b538SAndroid Build Coastguard Worker va_copy(ap_copy, ap);
49*6777b538SAndroid Build Coastguard Worker
50*6777b538SAndroid Build Coastguard Worker base::ScopedClearLastError last_error;
51*6777b538SAndroid Build Coastguard Worker int result = vsnprintf(stack_buf, std::size(stack_buf), format, ap_copy);
52*6777b538SAndroid Build Coastguard Worker va_end(ap_copy);
53*6777b538SAndroid Build Coastguard Worker
54*6777b538SAndroid Build Coastguard Worker if (result >= 0 && static_cast<size_t>(result) < std::size(stack_buf)) {
55*6777b538SAndroid Build Coastguard Worker // It fit.
56*6777b538SAndroid Build Coastguard Worker dst->append(stack_buf, static_cast<size_t>(result));
57*6777b538SAndroid Build Coastguard Worker return;
58*6777b538SAndroid Build Coastguard Worker }
59*6777b538SAndroid Build Coastguard Worker
60*6777b538SAndroid Build Coastguard Worker // Repeatedly increase buffer size until it fits.
61*6777b538SAndroid Build Coastguard Worker size_t mem_length = std::size(stack_buf);
62*6777b538SAndroid Build Coastguard Worker while (true) {
63*6777b538SAndroid Build Coastguard Worker if (result < 0) {
64*6777b538SAndroid Build Coastguard Worker #if BUILDFLAG(IS_WIN)
65*6777b538SAndroid Build Coastguard Worker // On Windows, vsnprintf always returns the number of characters in a
66*6777b538SAndroid Build Coastguard Worker // fully-formatted string, so if we reach this point, something else is
67*6777b538SAndroid Build Coastguard Worker // wrong and no amount of buffer-doubling is going to fix it.
68*6777b538SAndroid Build Coastguard Worker return;
69*6777b538SAndroid Build Coastguard Worker #else
70*6777b538SAndroid Build Coastguard Worker if (errno != 0 && errno != EOVERFLOW) {
71*6777b538SAndroid Build Coastguard Worker return;
72*6777b538SAndroid Build Coastguard Worker }
73*6777b538SAndroid Build Coastguard Worker // Try doubling the buffer size.
74*6777b538SAndroid Build Coastguard Worker mem_length *= 2;
75*6777b538SAndroid Build Coastguard Worker #endif
76*6777b538SAndroid Build Coastguard Worker } else {
77*6777b538SAndroid Build Coastguard Worker // We need exactly "result + 1" characters.
78*6777b538SAndroid Build Coastguard Worker mem_length = static_cast<size_t>(result) + 1;
79*6777b538SAndroid Build Coastguard Worker }
80*6777b538SAndroid Build Coastguard Worker
81*6777b538SAndroid Build Coastguard Worker if (mem_length > 32 * 1024 * 1024) {
82*6777b538SAndroid Build Coastguard Worker // That should be plenty, don't try anything larger. This protects
83*6777b538SAndroid Build Coastguard Worker // against huge allocations when using vsnprintf implementations that
84*6777b538SAndroid Build Coastguard Worker // return -1 for reasons other than overflow without setting errno.
85*6777b538SAndroid Build Coastguard Worker DLOG(WARNING) << "Unable to printf the requested string due to size.";
86*6777b538SAndroid Build Coastguard Worker return;
87*6777b538SAndroid Build Coastguard Worker }
88*6777b538SAndroid Build Coastguard Worker
89*6777b538SAndroid Build Coastguard Worker std::vector<char> mem_buf(mem_length);
90*6777b538SAndroid Build Coastguard Worker
91*6777b538SAndroid Build Coastguard Worker // NOTE: You can only use a va_list once. Since we're in a while loop, we
92*6777b538SAndroid Build Coastguard Worker // need to make a new copy each time so we don't use up the original.
93*6777b538SAndroid Build Coastguard Worker va_copy(ap_copy, ap);
94*6777b538SAndroid Build Coastguard Worker result = vsnprintf(&mem_buf[0], mem_length, format, ap_copy);
95*6777b538SAndroid Build Coastguard Worker va_end(ap_copy);
96*6777b538SAndroid Build Coastguard Worker
97*6777b538SAndroid Build Coastguard Worker if ((result >= 0) && (static_cast<size_t>(result) < mem_length)) {
98*6777b538SAndroid Build Coastguard Worker // It fit.
99*6777b538SAndroid Build Coastguard Worker dst->append(&mem_buf[0], static_cast<size_t>(result));
100*6777b538SAndroid Build Coastguard Worker return;
101*6777b538SAndroid Build Coastguard Worker }
102*6777b538SAndroid Build Coastguard Worker }
103*6777b538SAndroid Build Coastguard Worker }
104*6777b538SAndroid Build Coastguard Worker
105*6777b538SAndroid Build Coastguard Worker } // namespace base
106