Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(390)

Side by Side Diff: base/strings/safe_sprintf.h

Issue 18656004: Added a new SafeSPrintf() function that implements snprintf() in an async-safe-fashion (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Addressed Will's comments; renamed files to base/strings/safe_sprintf.* Created 7 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « base/strings/OWNERS ('k') | base/strings/safe_sprintf.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 // Copyright (c) 2013 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #ifndef BASE_STRINGS_SAFE_SPRINTF_H_
6 #define BASE_STRINGS_SAFE_SPRINTF_H_
7
8 #include <stddef.h>
9 #include <stdint.h>
10 #include <stdlib.h>
11
12 #if defined(__unix__)
13 // For ssize_t
14 #include <unistd.h>
15 #endif
16
17 #include "base/base_export.h"
18 #include "base/basictypes.h"
19
20 namespace base {
21 namespace strings {
22
23 #if defined(_MSC_VER)
24 // Define ssize_t inside of our namespace.
25 #if defined(_WIN64)
26 typedef __int64 ssize_t;
27 #else
28 typedef long ssize_t;
29 #endif
30 #endif
31
32 // SafeSPrintf() is a type-safe and async-signal-safe version of snprintf().
rvargas (doing something else) 2013/08/15 19:57:57 Can we be more specific (or more general? dunno) w
Markus (顧孟勤) 2013/08/15 20:31:20 This is just the one-line summary. If you keep rea
rvargas (doing something else) 2013/08/15 21:38:47 Yeah, I like the explicit phrasing of "guaranteed
Markus (顧孟勤) 2013/08/15 21:46:54 Done. OK, I tweaked the comments a little more. I
33 //
34 // SafeSNPrintf() is an alternative function signature that can be used when
35 // not dealing with fixed-sized buffers. When possible, SafeSPrintf() should
36 // always be used instead of SafeSNPrintf()
37 //
38 // These functions allow for formatting complicated messages from contexts that
39 // require strict async-signal-safety. In fact, it is safe to call them from
40 // any low-level execution context, as they are guaranteed to make no library
41 // or system calls.
42 //
43 // The only exception to this rule is that in debug builds the code calls
44 // RAW_CHECK() to help diagnose problems when the format string does not
45 // match the rest of the arguments. In release builds, no CHECK()s are used,
46 // and SafeSPrintf() instead returns an output string that expands only
47 // those arguments that match their format characters. Mismatched arguments
48 // are ignored.
49 //
50 // The code currently only supports a subset of format characters:
51 // %c, %o, %d, %x, %X, %p, and %s.
52 //
53 // SafeSPrintf() aims to be as liberal as reasonably possible. Integer-like
54 // values of arbitrary width can be passed to all of the format characters
55 // that expect integers. Thus, it is explicitly legal to pass an "int" to
56 // "%c", and output will automatically look at the LSB only. It is also
57 // explicitly legal to pass either signed or unsigned values, and the format
58 // characters will automatically interpret the arguments accordingly.
59 //
60 // It is still not legal to mix-and-match integer-like values with pointer
61 // values. For instance, you cannot pass a pointer to %x, nor can you pass an
62 // integer to %p.
63 //
64 // The one exception is "0" zero being accepted by "%p". This works-around
65 // the problem of C++ defining NULL as an integer-like value.
66 //
67 // All format characters take an optional width parameter. This must be a
68 // positive integer. For %d, %o, %x, %X and %p, if the width starts with
69 // a leading '0', padding is done with '0' instead of ' ' characters.
70 //
71 // There are a few features of snprintf()-style format strings, that
72 // SafeSPrintf() does not support at this time.
73 //
74 // If an actual user showed up, there is no particularly strong reason they
75 // couldn't be added. But that assumes that the trade-offs between complexity
76 // and utility are favorable.
77 //
78 // For example, adding support for negative padding widths, and for %n are all
79 // likely to be viewed positively. They are all clearly useful, low-risk, easy
80 // to test, don't jeopardize the async-signal-safety of the code, and overall
81 // have little impact on other parts of SafeSPrintf() function.
82 //
83 // On the other hands, adding support for alternate forms, positional
84 // arguments, grouping, wide characters, localization or floating point numbers
85 // are all unlikely to ever be added.
86 //
87 // SafeSPrintf() and SafeSNPrintf() mimic the behavior of snprintf() and they
88 // return the number of bytes needed to store the untruncated output. This
89 // does *not* include the terminating NUL byte.
90 //
91 // They return -1, iff a fatal error happened. This typically can only happen,
92 // if the buffer size is a) negative, or b) zero (i.e. not even the NUL byte
93 // can be written). The return value can never be larger than SSIZE_MAX-1.
94 // This ensures that the caller can always add one to the signed return code
95 // in order to determine the amount of storage that needs to be allocated.
96 //
97 // While the code supports type checking and while it is generally very careful
98 // to avoid printing incorrect values, it tends to be conservative in printing
99 // as much as possible, even when given incorrect parameters. Typically, in
100 // case of an error, the format string will not be expanded. (i.e. something
101 // like SafeSPrintf(buf, "%p %d", 1, 2) results in "%p 2"). See above for
102 // the use of RAW_CHECK() in debug builds, though.
103 //
104 // The pre-C++11 version cannot handle more than ten arguments.
105 //
106 // Basic example:
107 // char buf[20];
108 // base::strings::SafeSPrintf(buf, "The answer: %2d", 42);
109 //
110 // Example with dynamically sized buffer (async-signal-safe). This code won't
111 // work on Visual studio, as it requires dynamically allocating arrays on the
112 // stack. Consider picking a smaller value for |kMaxSize| if stack size is
113 // limited and known. On the other hand, if the parameters to SafeSNPrintf()
114 // are trusted and not controllable by the user, you can consider eliminating
115 // the check for |kMaxSize| altogether. The current value of SSIZE_MAX is
116 // essentially a no-op that just illustrates how to implement an upper bound:
117 // const size_t kInitialSize = 128;
118 // const size_t kMaxSize = std::numeric_limits<ssize_t>::max();
119 // size_t sz = kInitialSize;
rvargas (doing something else) 2013/08/15 19:57:57 nit: I know this is just an example, but do you mi
Markus (顧孟勤) 2013/08/15 20:31:20 I renamed it to "size". Is that better?
rvargas (doing something else) 2013/08/15 21:38:47 Totally :)
120 // for (;;) {
121 // char buf[sz];
122 // sz = SafeSNPrintf(buf, sz, "Error message \"%s\"\n", err) + 1;
123 // if (sizeof(buf) < kMaxSize && sz > kMaxSize) {
124 // sz = kMaxSize;
125 // continue;
126 // } else if (sz > sizeof(buf))
127 // continue;
128 // write(2, buf, sz-1);
129 // break;
130 // }
131
132 namespace internal {
133 // Helpers that use C++ overloading, templates, and specializations to deduce
134 // and record type information from function arguments. This allows us to
135 // later write a type-safe version of snprintf().
136
137 struct Arg {
138 enum Type { INT, UINT, STRING, POINTER };
139
140 // Any integer-like value.
141 Arg(signed char c) : i(c), width(sizeof(char)), type(INT) { }
142 Arg(unsigned char c) : i(c), width(sizeof(char)), type(UINT) { }
143 Arg(signed short j) : i(j), width(sizeof(short)), type(INT) { }
144 Arg(unsigned short j) : i(j), width(sizeof(short)), type(UINT) { }
145 Arg(signed int j) : i(j), width(sizeof(int)), type(INT) { }
146 Arg(unsigned int j) : i(j), width(sizeof(int)), type(UINT) { }
147 Arg(signed long j) : i(j), width(sizeof(long)), type(INT) { }
148 Arg(unsigned long j) : i(j), width(sizeof(long)), type(UINT) { }
149 Arg(signed long long j) : i(j), width(sizeof(long long)), type(INT) { }
150 Arg(unsigned long long j) : i(j), width(sizeof(long long)), type(UINT) { }
151
152 // A C-style text string.
153 Arg(const char* s) : str(s), type(STRING) { }
154 Arg(char* s) : str(s), type(STRING) { }
155
156 // Any pointer value that can be cast to a "void*".
157 template<class T> Arg(T* p) : ptr((void*)p), type(POINTER) { }
158
159 union {
160 // An integer-like value.
161 struct {
162 int64_t i;
163 unsigned char width;
164 };
165
166 // A C-style text string.
167 const char* str;
168
169 // A pointer to an arbitrary object.
170 const void* ptr;
171 };
172 const enum Type type;
173 };
174
175 // This is the internal function that performs the actual formatting of
176 // an snprintf()-style format string.
177 BASE_EXPORT ssize_t SafeSNPrintf(char* buf, size_t sz, const char* fmt,
178 const Arg* args, size_t max_args);
179
180 #if !defined(NDEBUG)
181 // In debug builds, allow unit tests to artificially lower the kSSizeMax
182 // constant that is used as a hard upper-bound for all buffers. In normal
183 // use, this constant should always be std::numeric_limits<ssize_t>::max().
184 BASE_EXPORT void SetSafeSPrintfSSizeMax(size_t max);
rvargas (doing something else) 2013/08/15 19:57:57 If these are use only for tests they should be nam
Markus (顧孟勤) 2013/08/15 20:31:20 Ah, learned something new :-) I had seen other cod
rvargas (doing something else) 2013/08/15 21:38:47 I suspected something along those lines... I saw t
185 BASE_EXPORT size_t GetSafeSPrintfSSizeMax();
186 #endif
187
188 } // namespace internal
189
190 #if __cplusplus >= 201103 // C++11
191
192 template<typename... Args>
193 ssize_t SafeSNPrintf(char* buf, size_t N, const char* fmt, Args... args) {
194 // Use Arg() object to record type information and then copy arguments to an
195 // array to make it easier to iterate over them.
196 const internal::Arg arg_array[] = { args... };
197 return internal::SafeSNPrintf(buf, N, fmt, arg_array, arraysize(arg_array));
198 }
199
200 template<size_t N, typename... Args>
201 ssize_t SafeSPrintf(char (&buf)[N], const char* fmt, Args... args) {
202 // Use Arg() object to record type information and then copy arguments to an
203 // array to make it easier to iterate over them.
204 const internal::Arg arg_array[] = { args... };
205 return internal::SafeSNPrintf(buf, N, fmt, arg_array, arraysize(arg_array));
206 }
207
208 #else // Pre-C++11
209
210 // TODO(markus): C++11 has a much more concise and readable solution for
211 // expressing what we are doing here. Delete the fall-back code for older
212 // compilers as soon as we have fully switched to C++11.
213
214 template<class T0, class T1, class T2, class T3, class T4,
215 class T5, class T6, class T7, class T8, class T9>
216 ssize_t SafeSNPrintf(char* buf, size_t N, const char* fmt,
217 T0 arg0, T1 arg1, T2 arg2, T3 arg3, T4 arg4,
218 T5 arg5, T6 arg6, T7 arg7, T8 arg8, T9 arg9) {
219 // Use Arg() object to record type information and then copy arguments to an
220 // array to make it easier to iterate over them.
221 const internal::Arg arg_array[] = {
222 arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9
223 };
224 return internal::SafeSNPrintf(buf, N, fmt, arg_array, arraysize(arg_array));
225 }
226
227 template<size_t N,
228 class T0, class T1, class T2, class T3, class T4,
229 class T5, class T6, class T7, class T8, class T9>
230 ssize_t SafeSPrintf(char (&buf)[N], const char* fmt,
231 T0 arg0, T1 arg1, T2 arg2, T3 arg3, T4 arg4,
232 T5 arg5, T6 arg6, T7 arg7, T8 arg8, T9 arg9) {
233 // Use Arg() object to record type information and then copy arguments to an
234 // array to make it easier to iterate over them.
235 const internal::Arg arg_array[] = {
236 arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9
237 };
238 return internal::SafeSNPrintf(buf, N, fmt, arg_array, arraysize(arg_array));
239 }
240
241 template<class T0, class T1, class T2, class T3, class T4,
242 class T5, class T6, class T7, class T8>
243 ssize_t SafeSNPrintf(char* buf, size_t N, const char* fmt,
244 T0 arg0, T1 arg1, T2 arg2, T3 arg3, T4 arg4,
245 T5 arg5, T6 arg6, T7 arg7, T8 arg8) {
246 // Use Arg() object to record type information and then copy arguments to an
247 // array to make it easier to iterate over them.
248 const internal::Arg arg_array[] = {
249 arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8
250 };
251 return internal::SafeSNPrintf(buf, N, fmt, arg_array, arraysize(arg_array));
252 }
253
254 template<size_t N,
255 class T0, class T1, class T2, class T3, class T4, class T5,
256 class T6, class T7, class T8>
257 ssize_t SafeSPrintf(char (&buf)[N], const char* fmt,
258 T0 arg0, T1 arg1, T2 arg2, T3 arg3, T4 arg4,
259 T5 arg5, T6 arg6, T7 arg7, T8 arg8) {
260 // Use Arg() object to record type information and then copy arguments to an
261 // array to make it easier to iterate over them.
262 const internal::Arg arg_array[] = {
263 arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8
264 };
265 return internal::SafeSNPrintf(buf, N, fmt, arg_array, arraysize(arg_array));
266 }
267
268 template<class T0, class T1, class T2, class T3, class T4, class T5,
269 class T6, class T7>
270 ssize_t SafeSNPrintf(char* buf, size_t N, const char* fmt,
271 T0 arg0, T1 arg1, T2 arg2, T3 arg3, T4 arg4,
272 T5 arg5, T6 arg6, T7 arg7) {
273 // Use Arg() object to record type information and then copy arguments to an
274 // array to make it easier to iterate over them.
275 const internal::Arg arg_array[] = {
276 arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7
277 };
278 return internal::SafeSNPrintf(buf, N, fmt, arg_array, arraysize(arg_array));
279 }
280
281 template<size_t N,
282 class T0, class T1, class T2, class T3, class T4, class T5,
283 class T6, class T7>
284 ssize_t SafeSPrintf(char (&buf)[N], const char* fmt,
285 T0 arg0, T1 arg1, T2 arg2, T3 arg3, T4 arg4,
286 T5 arg5, T6 arg6, T7 arg7) {
287 // Use Arg() object to record type information and then copy arguments to an
288 // array to make it easier to iterate over them.
289 const internal::Arg arg_array[] = {
290 arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7
291 };
292 return internal::SafeSNPrintf(buf, N, fmt, arg_array, arraysize(arg_array));
293 }
294
295 template<class T0, class T1, class T2, class T3, class T4, class T5,
296 class T6>
297 ssize_t SafeSNPrintf(char* buf, size_t N, const char* fmt,
298 T0 arg0, T1 arg1, T2 arg2, T3 arg3, T4 arg4,
299 T5 arg5, T6 arg6) {
300 // Use Arg() object to record type information and then copy arguments to an
301 // array to make it easier to iterate over them.
302 const internal::Arg arg_array[] = {
303 arg0, arg1, arg2, arg3, arg4, arg5, arg6
304 };
305 return internal::SafeSNPrintf(buf, N, fmt, arg_array, arraysize(arg_array));
306 }
307
308 template<size_t N,
309 class T0, class T1, class T2, class T3, class T4, class T5,
310 class T6>
311 ssize_t SafeSPrintf(char (&buf)[N], const char* fmt,
312 T0 arg0, T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5,
313 T6 arg6) {
314 // Use Arg() object to record type information and then copy arguments to an
315 // array to make it easier to iterate over them.
316 const internal::Arg arg_array[] = {
317 arg0, arg1, arg2, arg3, arg4, arg5, arg6
318 };
319 return internal::SafeSNPrintf(buf, N, fmt, arg_array, arraysize(arg_array));
320 }
321
322 template<class T0, class T1, class T2, class T3, class T4, class T5>
323 ssize_t SafeSNPrintf(char* buf, size_t N, const char* fmt,
324 T0 arg0, T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5) {
325 // Use Arg() object to record type information and then copy arguments to an
326 // array to make it easier to iterate over them.
327 const internal::Arg arg_array[] = { arg0, arg1, arg2, arg3, arg4, arg5 };
328 return internal::SafeSNPrintf(buf, N, fmt, arg_array, arraysize(arg_array));
329 }
330
331 template<size_t N,
332 class T0, class T1, class T2, class T3, class T4, class T5>
333 ssize_t SafeSPrintf(char (&buf)[N], const char* fmt,
334 T0 arg0, T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5) {
335 // Use Arg() object to record type information and then copy arguments to an
336 // array to make it easier to iterate over them.
337 const internal::Arg arg_array[] = { arg0, arg1, arg2, arg3, arg4, arg5 };
338 return internal::SafeSNPrintf(buf, N, fmt, arg_array, arraysize(arg_array));
339 }
340
341 template<class T0, class T1, class T2, class T3, class T4>
342 ssize_t SafeSNPrintf(char* buf, size_t N, const char* fmt,
343 T0 arg0, T1 arg1, T2 arg2, T3 arg3, T4 arg4) {
344 // Use Arg() object to record type information and then copy arguments to an
345 // array to make it easier to iterate over them.
346 const internal::Arg arg_array[] = { arg0, arg1, arg2, arg3, arg4 };
347 return internal::SafeSNPrintf(buf, N, fmt, arg_array, arraysize(arg_array));
348 }
349
350 template<size_t N, class T0, class T1, class T2, class T3, class T4>
351 ssize_t SafeSPrintf(char (&buf)[N], const char* fmt, T0 arg0, T1 arg1,
352 T2 arg2, T3 arg3, T4 arg4) {
353 // Use Arg() object to record type information and then copy arguments to an
354 // array to make it easier to iterate over them.
355 const internal::Arg arg_array[] = { arg0, arg1, arg2, arg3, arg4 };
356 return internal::SafeSNPrintf(buf, N, fmt, arg_array, arraysize(arg_array));
357 }
358
359 template<class T0, class T1, class T2, class T3>
360 ssize_t SafeSNPrintf(char* buf, size_t N, const char* fmt,
361 T0 arg0, T1 arg1, T2 arg2, T3 arg3) {
362 // Use Arg() object to record type information and then copy arguments to an
363 // array to make it easier to iterate over them.
364 const internal::Arg arg_array[] = { arg0, arg1, arg2, arg3 };
365 return internal::SafeSNPrintf(buf, N, fmt, arg_array, arraysize(arg_array));
366 }
367
368 template<size_t N, class T0, class T1, class T2, class T3>
369 ssize_t SafeSPrintf(char (&buf)[N], const char* fmt,
370 T0 arg0, T1 arg1, T2 arg2, T3 arg3) {
371 // Use Arg() object to record type information and then copy arguments to an
372 // array to make it easier to iterate over them.
373 const internal::Arg arg_array[] = { arg0, arg1, arg2, arg3 };
374 return internal::SafeSNPrintf(buf, N, fmt, arg_array, arraysize(arg_array));
375 }
376
377 template<class T0, class T1, class T2>
378 ssize_t SafeSNPrintf(char* buf, size_t N, const char* fmt,
379 T0 arg0, T1 arg1, T2 arg2) {
380 // Use Arg() object to record type information and then copy arguments to an
381 // array to make it easier to iterate over them.
382 const internal::Arg arg_array[] = { arg0, arg1, arg2 };
383 return internal::SafeSNPrintf(buf, N, fmt, arg_array, arraysize(arg_array));
384 }
385
386 template<size_t N, class T0, class T1, class T2>
387 ssize_t SafeSPrintf(char (&buf)[N], const char* fmt, T0 arg0, T1 arg1,
388 T2 arg2) {
389 // Use Arg() object to record type information and then copy arguments to an
390 // array to make it easier to iterate over them.
391 const internal::Arg arg_array[] = { arg0, arg1, arg2 };
392 return internal::SafeSNPrintf(buf, N, fmt, arg_array, arraysize(arg_array));
393 }
394
395 template<class T0, class T1>
396 ssize_t SafeSNPrintf(char* buf, size_t N, const char* fmt, T0 arg0, T1 arg1) {
397 // Use Arg() object to record type information and then copy arguments to an
398 // array to make it easier to iterate over them.
399 const internal::Arg arg_array[] = { arg0, arg1 };
400 return internal::SafeSNPrintf(buf, N, fmt, arg_array, arraysize(arg_array));
401 }
402
403 template<size_t N, class T0, class T1>
404 ssize_t SafeSPrintf(char (&buf)[N], const char* fmt, T0 arg0, T1 arg1) {
405 // Use Arg() object to record type information and then copy arguments to an
406 // array to make it easier to iterate over them.
407 const internal::Arg arg_array[] = { arg0, arg1 };
408 return internal::SafeSNPrintf(buf, N, fmt, arg_array, arraysize(arg_array));
409 }
410
411 template<class T0>
412 ssize_t SafeSNPrintf(char* buf, size_t N, const char* fmt, T0 arg0) {
413 // Use Arg() object to record type information and then copy arguments to an
414 // array to make it easier to iterate over them.
415 const internal::Arg arg_array[] = { arg0 };
416 return internal::SafeSNPrintf(buf, N, fmt, arg_array, arraysize(arg_array));
417 }
418
419 template<size_t N, class T0>
420 ssize_t SafeSPrintf(char (&buf)[N], const char* fmt, T0 arg0) {
421 // Use Arg() object to record type information and then copy arguments to an
422 // array to make it easier to iterate over them.
423 const internal::Arg arg_array[] = { arg0 };
424 return internal::SafeSNPrintf(buf, N, fmt, arg_array, arraysize(arg_array));
425 }
426 #endif
427
428 // Fast-path when we don't actually need to substitute any arguments.
429 BASE_EXPORT ssize_t SafeSNPrintf(char* buf, size_t N, const char* fmt);
430 template<size_t N>
431 inline ssize_t SafeSPrintf(char (&buf)[N], const char* fmt) {
432 return SafeSNPrintf(buf, N, fmt);
433 }
434
435 } // namespace strings
436 } // namespace base
437
438 #endif // BASE_STRINGS_SAFE_SPRINTF_H_
OLDNEW
« no previous file with comments | « base/strings/OWNERS ('k') | base/strings/safe_sprintf.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698