/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) { |
36 | 753 | if (result >= 0) { |
37 | | // Normal case -- everything fit. |
38 | 753 | dst->append(space, result); |
39 | 753 | return; |
40 | 753 | } |
41 | | |
42 | 0 | if (IS__MSC_VER) { |
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) { |
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) { |
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) { |
118 | 0 | cstr[i] = v[i].c_str(); |
119 | 0 | } |
120 | 0 | for (int i = v.size(); i < arraysize(cstr); ++i) { |
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 | } |