tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

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