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