/src/sentencepiece/third_party/protobuf-lite/stringprintf.cc
Line | Count | Source (jump to first uncovered line) |
1 | | // Protocol Buffers - Google's data interchange format |
2 | | // Copyright 2012 Google Inc. All rights reserved. |
3 | | // https://developers.google.com/protocol-buffers/ |
4 | | // |
5 | | // Redistribution and use in source and binary forms, with or without |
6 | | // modification, are permitted provided that the following conditions are |
7 | | // met: |
8 | | // |
9 | | // * Redistributions of source code must retain the above copyright |
10 | | // notice, this list of conditions and the following disclaimer. |
11 | | // * Redistributions in binary form must reproduce the above |
12 | | // copyright notice, this list of conditions and the following disclaimer |
13 | | // in the documentation and/or other materials provided with the |
14 | | // distribution. |
15 | | // * Neither the name of Google Inc. nor the names of its |
16 | | // contributors may be used to endorse or promote products derived from |
17 | | // this software without specific prior written permission. |
18 | | // |
19 | | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
20 | | // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
21 | | // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
22 | | // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
23 | | // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
24 | | // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
25 | | // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
26 | | // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
27 | | // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
28 | | // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
29 | | // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
30 | | |
31 | | // from google3/base/stringprintf.cc |
32 | | |
33 | | #include <google/protobuf/stubs/stringprintf.h> |
34 | | |
35 | | #include <errno.h> |
36 | | #include <stdarg.h> // For va_list and related operations |
37 | | #include <stdio.h> // MSVC requires this for _vsnprintf |
38 | | #include <vector> |
39 | | |
40 | | #include <google/protobuf/stubs/common.h> |
41 | | #include <google/protobuf/stubs/logging.h> |
42 | | |
43 | | namespace google { |
44 | | namespace protobuf { |
45 | | |
46 | | #ifdef _MSC_VER |
47 | | enum { IS_COMPILER_MSVC = 1 }; |
48 | | #ifndef va_copy |
49 | | // Define va_copy for MSVC. This is a hack, assuming va_list is simply a |
50 | | // pointer into the stack and is safe to copy. |
51 | | #define va_copy(dest, src) ((dest) = (src)) |
52 | | #endif |
53 | | #else |
54 | | enum { IS_COMPILER_MSVC = 0 }; |
55 | | #endif |
56 | | |
57 | 0 | void StringAppendV(std::string* dst, const char* format, va_list ap) { |
58 | | // First try with a small fixed size buffer |
59 | 0 | static const int kSpaceLength = 1024; |
60 | 0 | char space[kSpaceLength]; |
61 | | |
62 | | // It's possible for methods that use a va_list to invalidate |
63 | | // the data in it upon use. The fix is to make a copy |
64 | | // of the structure before using it and use that copy instead. |
65 | 0 | va_list backup_ap; |
66 | 0 | va_copy(backup_ap, ap); |
67 | 0 | int result = vsnprintf(space, kSpaceLength, format, backup_ap); |
68 | 0 | va_end(backup_ap); |
69 | |
|
70 | 0 | if (result < kSpaceLength) { |
71 | 0 | if (result >= 0) { |
72 | | // Normal case -- everything fit. |
73 | 0 | dst->append(space, result); |
74 | 0 | return; |
75 | 0 | } |
76 | | |
77 | 0 | if (IS_COMPILER_MSVC) { |
78 | | // Error or MSVC running out of space. MSVC 8.0 and higher |
79 | | // can be asked about space needed with the special idiom below: |
80 | 0 | va_copy(backup_ap, ap); |
81 | 0 | result = vsnprintf(nullptr, 0, format, backup_ap); |
82 | 0 | va_end(backup_ap); |
83 | 0 | } |
84 | |
|
85 | 0 | if (result < 0) { |
86 | | // Just an error. |
87 | 0 | return; |
88 | 0 | } |
89 | 0 | } |
90 | | |
91 | | // Increase the buffer size to the size requested by vsnprintf, |
92 | | // plus one for the closing \0. |
93 | 0 | int length = result+1; |
94 | 0 | char* buf = new char[length]; |
95 | | |
96 | | // Restore the va_list before we use it again |
97 | 0 | va_copy(backup_ap, ap); |
98 | 0 | result = vsnprintf(buf, length, format, backup_ap); |
99 | 0 | va_end(backup_ap); |
100 | |
|
101 | 0 | if (result >= 0 && result < length) { |
102 | | // It fit |
103 | 0 | dst->append(buf, result); |
104 | 0 | } |
105 | 0 | delete[] buf; |
106 | 0 | } |
107 | | |
108 | 0 | std::string StringPrintf(const char* format, ...) { |
109 | 0 | va_list ap; |
110 | 0 | va_start(ap, format); |
111 | 0 | std::string result; |
112 | 0 | StringAppendV(&result, format, ap); |
113 | 0 | va_end(ap); |
114 | 0 | return result; |
115 | 0 | } |
116 | | |
117 | 0 | const std::string& SStringPrintf(std::string* dst, const char* format, ...) { |
118 | 0 | va_list ap; |
119 | 0 | va_start(ap, format); |
120 | 0 | dst->clear(); |
121 | 0 | StringAppendV(dst, format, ap); |
122 | 0 | va_end(ap); |
123 | 0 | return *dst; |
124 | 0 | } |
125 | | |
126 | 0 | void StringAppendF(std::string* dst, const char* format, ...) { |
127 | 0 | va_list ap; |
128 | 0 | va_start(ap, format); |
129 | 0 | StringAppendV(dst, format, ap); |
130 | 0 | va_end(ap); |
131 | 0 | } |
132 | | |
133 | | // Max arguments supported by StringPrintVector |
134 | | const int kStringPrintfVectorMaxArgs = 32; |
135 | | |
136 | | // An empty block of zero for filler arguments. This is const so that if |
137 | | // printf tries to write to it (via %n) then the program gets a SIGSEGV |
138 | | // and we can fix the problem or protect against an attack. |
139 | | static const char string_printf_empty_block[256] = { '\0' }; |
140 | | |
141 | | std::string StringPrintfVector(const char* format, |
142 | 0 | const std::vector<std::string>& v) { |
143 | 0 | GOOGLE_CHECK_LE(v.size(), kStringPrintfVectorMaxArgs) |
144 | 0 | << "StringPrintfVector currently only supports up to " |
145 | 0 | << kStringPrintfVectorMaxArgs << " arguments. " |
146 | 0 | << "Feel free to add support for more if you need it."; |
147 | | |
148 | | // Add filler arguments so that bogus format+args have a harder time |
149 | | // crashing the program, corrupting the program (%n), |
150 | | // or displaying random chunks of memory to users. |
151 | |
|
152 | 0 | const char* cstr[kStringPrintfVectorMaxArgs]; |
153 | 0 | for (int i = 0; i < v.size(); ++i) { |
154 | 0 | cstr[i] = v[i].c_str(); |
155 | 0 | } |
156 | 0 | for (int i = v.size(); i < GOOGLE_ARRAYSIZE(cstr); ++i) { |
157 | 0 | cstr[i] = &string_printf_empty_block[0]; |
158 | 0 | } |
159 | | |
160 | | // I do not know any way to pass kStringPrintfVectorMaxArgs arguments, |
161 | | // or any way to build a va_list by hand, or any API for printf |
162 | | // that accepts an array of arguments. The best I can do is stick |
163 | | // this COMPILE_ASSERT right next to the actual statement. |
164 | |
|
165 | 0 | GOOGLE_COMPILE_ASSERT(kStringPrintfVectorMaxArgs == 32, arg_count_mismatch); |
166 | 0 | return StringPrintf(format, |
167 | 0 | cstr[0], cstr[1], cstr[2], cstr[3], cstr[4], |
168 | 0 | cstr[5], cstr[6], cstr[7], cstr[8], cstr[9], |
169 | 0 | cstr[10], cstr[11], cstr[12], cstr[13], cstr[14], |
170 | 0 | cstr[15], cstr[16], cstr[17], cstr[18], cstr[19], |
171 | 0 | cstr[20], cstr[21], cstr[22], cstr[23], cstr[24], |
172 | 0 | cstr[25], cstr[26], cstr[27], cstr[28], cstr[29], |
173 | 0 | cstr[30], cstr[31]); |
174 | 0 | } |
175 | | } // namespace protobuf |
176 | | } // namespace google |