/root/doris/be/src/gutil/stringprintf.cc
| Line | Count | Source (jump to first uncovered line) | 
| 1 |  | // Copyright 2002 and onwards Google Inc. | 
| 2 |  |  | 
| 3 |  | #include "gutil/stringprintf.h" | 
| 4 |  |  | 
| 5 |  | #include <stdarg.h> // For va_list and related operations | 
| 6 |  | #include <stdio.h>  // MSVC requires this for _vsnprintf | 
| 7 |  | #include <vector> | 
| 8 |  | #include <ostream> | 
| 9 |  |  | 
| 10 |  | using std::vector; | 
| 11 |  | #include "common/logging.h" | 
| 12 |  |  | 
| 13 |  | // IWYU pragma: no_include <butil/macros.h> | 
| 14 |  | #include "gutil/macros.h" // IWYU pragma: keep | 
| 15 |  |  | 
| 16 |  | #ifdef _MSC_VER | 
| 17 |  | enum { IS__MSC_VER = 1 }; | 
| 18 |  | #else | 
| 19 |  | enum { IS__MSC_VER = 0 }; | 
| 20 |  | #endif | 
| 21 |  |  | 
| 22 | 753 | void StringAppendV(string* dst, const char* format, va_list ap) { | 
| 23 |  |     // First try with a small fixed size buffer | 
| 24 | 753 |     static const int kSpaceLength = 1024; | 
| 25 | 753 |     char space[kSpaceLength]; | 
| 26 |  |  | 
| 27 |  |     // It's possible for methods that use a va_list to invalidate | 
| 28 |  |     // the data in it upon use.  The fix is to make a copy | 
| 29 |  |     // of the structure before using it and use that copy instead. | 
| 30 | 753 |     va_list backup_ap; | 
| 31 | 753 |     va_copy(backup_ap, ap); | 
| 32 | 753 |     int result = vsnprintf(space, kSpaceLength, format, backup_ap); | 
| 33 | 753 |     va_end(backup_ap); | 
| 34 |  |  | 
| 35 | 753 |     if (result < kSpaceLength) {  Branch (35:9): [True: 753, False: 0]
 | 
| 36 | 753 |         if (result >= 0) {  Branch (36:13): [True: 753, False: 0]
 | 
| 37 |  |             // Normal case -- everything fit. | 
| 38 | 753 |             dst->append(space, result); | 
| 39 | 753 |             return; | 
| 40 | 753 |         } | 
| 41 |  |  | 
| 42 | 0 |         if (IS__MSC_VER) {  Branch (42:13): [Folded - Ignored]
 | 
| 43 |  |             // Error or MSVC running out of space.  MSVC 8.0 and higher | 
| 44 |  |             // can be asked about space needed with the special idiom below: | 
| 45 | 0 |             va_copy(backup_ap, ap); | 
| 46 | 0 |             result = vsnprintf(nullptr, 0, format, backup_ap); | 
| 47 | 0 |             va_end(backup_ap); | 
| 48 | 0 |         } | 
| 49 |  | 
 | 
| 50 | 0 |         if (result < 0) {  Branch (50:13): [True: 0, False: 0]
 | 
| 51 |  |             // Just an error. | 
| 52 | 0 |             return; | 
| 53 | 0 |         } | 
| 54 | 0 |     } | 
| 55 |  |  | 
| 56 |  |     // Increase the buffer size to the size requested by vsnprintf, | 
| 57 |  |     // plus one for the closing \0. | 
| 58 | 0 |     int length = result + 1; | 
| 59 | 0 |     auto buf = new char[length]; | 
| 60 |  |  | 
| 61 |  |     // Restore the va_list before we use it again | 
| 62 | 0 |     va_copy(backup_ap, ap); | 
| 63 | 0 |     result = vsnprintf(buf, length, format, backup_ap); | 
| 64 | 0 |     va_end(backup_ap); | 
| 65 |  | 
 | 
| 66 | 0 |     if (result >= 0 && result < length) {  Branch (66:9): [True: 0, False: 0]
  Branch (66:24): [True: 0, False: 0]
 | 
| 67 |  |         // It fit | 
| 68 | 0 |         dst->append(buf, result); | 
| 69 | 0 |     } | 
| 70 | 0 |     delete[] buf; | 
| 71 | 0 | } | 
| 72 |  |  | 
| 73 | 697 | string StringPrintf(const char* format, ...) { | 
| 74 | 697 |     va_list ap; | 
| 75 | 697 |     va_start(ap, format); | 
| 76 | 697 |     string result; | 
| 77 | 697 |     StringAppendV(&result, format, ap); | 
| 78 | 697 |     va_end(ap); | 
| 79 | 697 |     return result; | 
| 80 | 697 | } | 
| 81 |  |  | 
| 82 | 0 | const string& SStringPrintf(string* dst, const char* format, ...) { | 
| 83 | 0 |     va_list ap; | 
| 84 | 0 |     va_start(ap, format); | 
| 85 | 0 |     dst->clear(); | 
| 86 | 0 |     StringAppendV(dst, format, ap); | 
| 87 | 0 |     va_end(ap); | 
| 88 | 0 |     return *dst; | 
| 89 | 0 | } | 
| 90 |  |  | 
| 91 | 56 | void StringAppendF(string* dst, const char* format, ...) { | 
| 92 | 56 |     va_list ap; | 
| 93 | 56 |     va_start(ap, format); | 
| 94 | 56 |     StringAppendV(dst, format, ap); | 
| 95 | 56 |     va_end(ap); | 
| 96 | 56 | } | 
| 97 |  |  | 
| 98 |  | // Max arguments supported by StringPrintVector | 
| 99 |  | const int kStringPrintfVectorMaxArgs = 32; | 
| 100 |  |  | 
| 101 |  | // An empty block of zero for filler arguments.  This is const so that if | 
| 102 |  | // printf tries to write to it (via %n) then the program gets a SIGSEGV | 
| 103 |  | // and we can fix the problem or protect against an attack. | 
| 104 |  | static const char string_printf_empty_block[256] = {'\0'}; | 
| 105 |  |  | 
| 106 | 0 | string StringPrintfVector(const char* format, const vector<string>& v) { | 
| 107 | 0 |     CHECK_LE(v.size(), kStringPrintfVectorMaxArgs) | 
| 108 | 0 |             << "StringPrintfVector currently only supports up to " << kStringPrintfVectorMaxArgs | 
| 109 | 0 |             << " arguments. " | 
| 110 | 0 |             << "Feel free to add support for more if you need it."; | 
| 111 |  |  | 
| 112 |  |     // Add filler arguments so that bogus format+args have a harder time | 
| 113 |  |     // crashing the program, corrupting the program (%n), | 
| 114 |  |     // or displaying random chunks of memory to users. | 
| 115 |  | 
 | 
| 116 | 0 |     const char* cstr[kStringPrintfVectorMaxArgs]; | 
| 117 | 0 |     for (int i = 0; i < v.size(); ++i) {  Branch (117:21): [True: 0, False: 0]
 | 
| 118 | 0 |         cstr[i] = v[i].c_str(); | 
| 119 | 0 |     } | 
| 120 | 0 |     for (int i = v.size(); i < arraysize(cstr); ++i) {  Branch (120:28): [True: 0, False: 0]
 | 
| 121 | 0 |         cstr[i] = &string_printf_empty_block[0]; | 
| 122 | 0 |     } | 
| 123 |  |  | 
| 124 |  |     // I do not know any way to pass kStringPrintfVectorMaxArgs arguments, | 
| 125 |  |     // or any way to build a va_list by hand, or any API for printf | 
| 126 |  |     // that accepts an array of arguments.  The best I can do is stick | 
| 127 |  |     // this COMPILE_ASSERT right next to the actual statement. | 
| 128 |  | 
 | 
| 129 | 0 |     COMPILE_ASSERT(kStringPrintfVectorMaxArgs == 32, arg_count_mismatch); | 
| 130 | 0 |     return StringPrintf(format, cstr[0], cstr[1], cstr[2], cstr[3], cstr[4], cstr[5], cstr[6], | 
| 131 | 0 |                         cstr[7], cstr[8], cstr[9], cstr[10], cstr[11], cstr[12], cstr[13], cstr[14], | 
| 132 | 0 |                         cstr[15], cstr[16], cstr[17], cstr[18], cstr[19], cstr[20], cstr[21], | 
| 133 | 0 |                         cstr[22], cstr[23], cstr[24], cstr[25], cstr[26], cstr[27], cstr[28], | 
| 134 | 0 |                         cstr[29], cstr[30], cstr[31]); | 
| 135 | 0 | } |