stringprintf.cc (3017B)
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 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 28 std::string StringPrintV(const char* format, va_list ap) { 29 std::string result; 30 StringAppendV(&result, format, ap); 31 return result; 32 } 33 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 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