/Users/deen/code/yugabyte-db/src/yb/gutil/stringprintf.cc
Line | Count | Source (jump to first uncovered line) |
1 | | // Copyright 2002 and onwards Google Inc. |
2 | | // |
3 | | // The following only applies to changes made to this file as part of YugaByte development. |
4 | | // |
5 | | // Portions Copyright (c) YugaByte, Inc. |
6 | | // |
7 | | // Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except |
8 | | // in compliance with the License. You may obtain a copy of the License at |
9 | | // |
10 | | // http://www.apache.org/licenses/LICENSE-2.0 |
11 | | // |
12 | | // Unless required by applicable law or agreed to in writing, software distributed under the License |
13 | | // is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express |
14 | | // or implied. See the License for the specific language governing permissions and limitations |
15 | | // under the License. |
16 | | // |
17 | | |
18 | | #include "yb/gutil/stringprintf.h" |
19 | | |
20 | | #include <errno.h> |
21 | | #include <stdarg.h> // For va_list and related operations |
22 | | #include <stdio.h> // MSVC requires this for _vsnprintf |
23 | | |
24 | | #include <vector> |
25 | | |
26 | | #include <glog/logging.h> |
27 | | |
28 | | #include "yb/gutil/macros.h" |
29 | | |
30 | | using std::vector; |
31 | | |
32 | | #ifdef _MSC_VER |
33 | | enum { IS__MSC_VER = 1 }; |
34 | | #else |
35 | | enum { IS__MSC_VER = 0 }; |
36 | | #endif |
37 | | |
38 | 43.4M | void StringAppendV(string* dst, const char* format, va_list ap) { |
39 | | // First try with a small fixed size buffer |
40 | 43.4M | static const int kSpaceLength = 1024; |
41 | 43.4M | char space[kSpaceLength]; |
42 | | |
43 | | // It's possible for methods that use a va_list to invalidate |
44 | | // the data in it upon use. The fix is to make a copy |
45 | | // of the structure before using it and use that copy instead. |
46 | 43.4M | va_list backup_ap; |
47 | 43.4M | va_copy(backup_ap, ap); |
48 | 43.4M | int result = vsnprintf(space, kSpaceLength, format, backup_ap); |
49 | 43.4M | va_end(backup_ap); |
50 | | |
51 | 43.4M | if (result < kSpaceLength) { |
52 | 43.4M | if (result >= 0) { |
53 | | // Normal case -- everything fit. |
54 | 43.4M | dst->append(space, result); |
55 | 43.4M | return; |
56 | 43.4M | } |
57 | | |
58 | 18.4E | if (IS__MSC_VER) { |
59 | | // Error or MSVC running out of space. MSVC 8.0 and higher |
60 | | // can be asked about space needed with the special idiom below: |
61 | 0 | va_copy(backup_ap, ap); |
62 | 0 | result = vsnprintf(nullptr, 0, format, backup_ap); |
63 | 0 | va_end(backup_ap); |
64 | 0 | } |
65 | | |
66 | 18.4E | if (result < 0) { |
67 | | // Just an error. |
68 | 0 | return; |
69 | 0 | } |
70 | 18.4E | } |
71 | | |
72 | | // Increase the buffer size to the size requested by vsnprintf, |
73 | | // plus one for the closing \0. |
74 | 18.4E | int length = result+1; |
75 | 18.4E | auto buf = new char[length]; |
76 | | |
77 | | // Restore the va_list before we use it again |
78 | 18.4E | va_copy(backup_ap, ap); |
79 | 18.4E | result = vsnprintf(buf, length, format, backup_ap); |
80 | 18.4E | va_end(backup_ap); |
81 | | |
82 | 18.4E | if (result >= 0 && result < length) { |
83 | | // It fit |
84 | 0 | dst->append(buf, result); |
85 | 0 | } |
86 | 18.4E | delete[] buf; |
87 | 18.4E | } |
88 | | |
89 | | |
90 | 41.8M | string StringPrintf(const char* format, ...) { |
91 | 41.8M | va_list ap; |
92 | 41.8M | va_start(ap, format); |
93 | 41.8M | string result; |
94 | 41.8M | StringAppendV(&result, format, ap); |
95 | 41.8M | va_end(ap); |
96 | 41.8M | return result; |
97 | 41.8M | } |
98 | | |
99 | 0 | const string& SStringPrintf(string* dst, const char* format, ...) { |
100 | 0 | va_list ap; |
101 | 0 | va_start(ap, format); |
102 | 0 | dst->clear(); |
103 | 0 | StringAppendV(dst, format, ap); |
104 | 0 | va_end(ap); |
105 | 0 | return *dst; |
106 | 0 | } |
107 | | |
108 | 1.54M | void StringAppendF(string* dst, const char* format, ...) { |
109 | 1.54M | va_list ap; |
110 | 1.54M | va_start(ap, format); |
111 | 1.54M | StringAppendV(dst, format, ap); |
112 | 1.54M | va_end(ap); |
113 | 1.54M | } |
114 | | |
115 | | // Max arguments supported by StringPrintVector |
116 | | const int kStringPrintfVectorMaxArgs = 32; |
117 | | |
118 | | // An empty block of zero for filler arguments. This is const so that if |
119 | | // printf tries to write to it (via %n) then the program gets a SIGSEGV |
120 | | // and we can fix the problem or protect against an attack. |
121 | | static const char string_printf_empty_block[256] = { '\0' }; |
122 | | |
123 | 0 | string StringPrintfVector(const char* format, const vector<string>& v) { |
124 | 0 | CHECK_LE(v.size(), kStringPrintfVectorMaxArgs) |
125 | 0 | << "StringPrintfVector currently only supports up to " |
126 | 0 | << kStringPrintfVectorMaxArgs << " arguments. " |
127 | 0 | << "Feel free to add support for more if you need it."; |
128 | | |
129 | | // Add filler arguments so that bogus format+args have a harder time |
130 | | // crashing the program, corrupting the program (%n), |
131 | | // or displaying random chunks of memory to users. |
132 | |
|
133 | 0 | const char* cstr[kStringPrintfVectorMaxArgs]; |
134 | 0 | for (size_t i = 0; i < v.size(); ++i) { |
135 | 0 | cstr[i] = v[i].c_str(); |
136 | 0 | } |
137 | 0 | for (size_t i = v.size(); i < arraysize(cstr); ++i) { |
138 | 0 | cstr[i] = &string_printf_empty_block[0]; |
139 | 0 | } |
140 | | |
141 | | // I do not know any way to pass kStringPrintfVectorMaxArgs arguments, |
142 | | // or any way to build a va_list by hand, or any API for printf |
143 | | // that accepts an array of arguments. The best I can do is stick |
144 | | // this COMPILE_ASSERT right next to the actual statement. |
145 | |
|
146 | 0 | COMPILE_ASSERT(kStringPrintfVectorMaxArgs == 32, arg_count_mismatch); |
147 | | // Getting these warnings from clang static analyzer: |
148 | | // warning: {2nd,3rd,4th,5th} function call argument is an uninitialized value |
149 | 0 | return StringPrintf(format, |
150 | 0 | cstr[0], cstr[1], cstr[2], cstr[3], cstr[4], |
151 | 0 | cstr[5], cstr[6], cstr[7], cstr[8], cstr[9], |
152 | 0 | cstr[10], cstr[11], cstr[12], cstr[13], cstr[14], |
153 | 0 | cstr[15], cstr[16], cstr[17], cstr[18], cstr[19], |
154 | 0 | cstr[20], cstr[21], cstr[22], cstr[23], cstr[24], |
155 | 0 | cstr[25], cstr[26], cstr[27], cstr[28], cstr[29], |
156 | 0 | cstr[30], cstr[31]); |
157 | 0 | } |