| // Copyright 2013 The Chromium Authors. All rights reserved. | 
 | // Use of this source code is governed by a BSD-style license that can be | 
 | // found in the LICENSE file. | 
 |  | 
 | #ifndef BASE_STRINGS_SAFE_SPRINTF_H_ | 
 | #define BASE_STRINGS_SAFE_SPRINTF_H_ | 
 |  | 
 | #include "build_config.h" | 
 |  | 
 | #include <stddef.h> | 
 | #include <stdint.h> | 
 | #include <stdlib.h> | 
 |  | 
 | #if defined(OS_POSIX) || defined(OS_FUCHSIA) | 
 | // For ssize_t | 
 | #include <unistd.h> | 
 | #endif | 
 |  | 
 | #include "base/base_export.h" | 
 |  | 
 | namespace base { | 
 | namespace strings { | 
 |  | 
 | #if defined(COMPILER_MSVC) | 
 | // Define ssize_t inside of our namespace. | 
 | #if defined(_WIN64) | 
 | typedef __int64 ssize_t; | 
 | #else | 
 | typedef long ssize_t; | 
 | #endif | 
 | #endif | 
 |  | 
 | // SafeSPrintf() is a type-safe and completely self-contained version of | 
 | // snprintf(). | 
 | // | 
 | // SafeSNPrintf() is an alternative function signature that can be used when | 
 | // not dealing with fixed-sized buffers. When possible, SafeSPrintf() should | 
 | // always be used instead of SafeSNPrintf() | 
 | // | 
 | // These functions allow for formatting complicated messages from contexts that | 
 | // require strict async-signal-safety. In fact, it is safe to call them from | 
 | // any low-level execution context, as they are guaranteed to make no library | 
 | // or system calls. It deliberately never touches "errno", either. | 
 | // | 
 | // The only exception to this rule is that in debug builds the code calls | 
 | // RAW_CHECK() to help diagnose problems when the format string does not | 
 | // match the rest of the arguments. In release builds, no CHECK()s are used, | 
 | // and SafeSPrintf() instead returns an output string that expands only | 
 | // those arguments that match their format characters. Mismatched arguments | 
 | // are ignored. | 
 | // | 
 | // The code currently only supports a subset of format characters: | 
 | //   %c, %o, %d, %x, %X, %p, and %s. | 
 | // | 
 | // SafeSPrintf() aims to be as liberal as reasonably possible. Integer-like | 
 | // values of arbitrary width can be passed to all of the format characters | 
 | // that expect integers. Thus, it is explicitly legal to pass an "int" to | 
 | // "%c", and output will automatically look at the LSB only. It is also | 
 | // explicitly legal to pass either signed or unsigned values, and the format | 
 | // characters will automatically interpret the arguments accordingly. | 
 | // | 
 | // It is still not legal to mix-and-match integer-like values with pointer | 
 | // values. For instance, you cannot pass a pointer to %x, nor can you pass an | 
 | // integer to %p. | 
 | // | 
 | // The one exception is "0" zero being accepted by "%p". This works-around | 
 | // the problem of C++ defining NULL as an integer-like value. | 
 | // | 
 | // All format characters take an optional width parameter. This must be a | 
 | // positive integer. For %d, %o, %x, %X and %p, if the width starts with | 
 | // a leading '0', padding is done with '0' instead of ' ' characters. | 
 | // | 
 | // There are a few features of snprintf()-style format strings, that | 
 | // SafeSPrintf() does not support at this time. | 
 | // | 
 | // If an actual user showed up, there is no particularly strong reason they | 
 | // couldn't be added. But that assumes that the trade-offs between complexity | 
 | // and utility are favorable. | 
 | // | 
 | // For example, adding support for negative padding widths, and for %n are all | 
 | // likely to be viewed positively. They are all clearly useful, low-risk, easy | 
 | // to test, don't jeopardize the async-signal-safety of the code, and overall | 
 | // have little impact on other parts of SafeSPrintf() function. | 
 | // | 
 | // On the other hands, adding support for alternate forms, positional | 
 | // arguments, grouping, wide characters, localization or floating point numbers | 
 | // are all unlikely to ever be added. | 
 | // | 
 | // SafeSPrintf() and SafeSNPrintf() mimic the behavior of snprintf() and they | 
 | // return the number of bytes needed to store the untruncated output. This | 
 | // does *not* include the terminating NUL byte. | 
 | // | 
 | // They return -1, iff a fatal error happened. This typically can only happen, | 
 | // if the buffer size is a) negative, or b) zero (i.e. not even the NUL byte | 
 | // can be written). The return value can never be larger than SSIZE_MAX-1. | 
 | // This ensures that the caller can always add one to the signed return code | 
 | // in order to determine the amount of storage that needs to be allocated. | 
 | // | 
 | // While the code supports type checking and while it is generally very careful | 
 | // to avoid printing incorrect values, it tends to be conservative in printing | 
 | // as much as possible, even when given incorrect parameters. Typically, in | 
 | // case of an error, the format string will not be expanded. (i.e. something | 
 | // like SafeSPrintf(buf, "%p %d", 1, 2) results in "%p 2"). See above for | 
 | // the use of RAW_CHECK() in debug builds, though. | 
 | // | 
 | // Basic example: | 
 | //   char buf[20]; | 
 | //   base::strings::SafeSPrintf(buf, "The answer: %2d", 42); | 
 | // | 
 | // Example with dynamically sized buffer (async-signal-safe). This code won't | 
 | // work on Visual studio, as it requires dynamically allocating arrays on the | 
 | // stack. Consider picking a smaller value for |kMaxSize| if stack size is | 
 | // limited and known. On the other hand, if the parameters to SafeSNPrintf() | 
 | // are trusted and not controllable by the user, you can consider eliminating | 
 | // the check for |kMaxSize| altogether. The current value of SSIZE_MAX is | 
 | // essentially a no-op that just illustrates how to implement an upper bound: | 
 | //   const size_t kInitialSize = 128; | 
 | //   const size_t kMaxSize = std::numeric_limits<ssize_t>::max(); | 
 | //   size_t size = kInitialSize; | 
 | //   for (;;) { | 
 | //     char buf[size]; | 
 | //     size = SafeSNPrintf(buf, size, "Error message \"%s\"\n", err) + 1; | 
 | //     if (sizeof(buf) < kMaxSize && size > kMaxSize) { | 
 | //       size = kMaxSize; | 
 | //       continue; | 
 | //     } else if (size > sizeof(buf)) | 
 | //       continue; | 
 | //     write(2, buf, size-1); | 
 | //     break; | 
 | //   } | 
 |  | 
 | namespace internal { | 
 | // Helpers that use C++ overloading, templates, and specializations to deduce | 
 | // and record type information from function arguments. This allows us to | 
 | // later write a type-safe version of snprintf(). | 
 |  | 
 | struct Arg { | 
 |   enum Type { INT, UINT, STRING, POINTER }; | 
 |  | 
 |   // Any integer-like value. | 
 |   Arg(signed char c) : type(INT) { | 
 |     integer.i = c; | 
 |     integer.width = sizeof(char); | 
 |   } | 
 |   Arg(unsigned char c) : type(UINT) { | 
 |     integer.i = c; | 
 |     integer.width = sizeof(char); | 
 |   } | 
 |   Arg(signed short j) : type(INT) { | 
 |     integer.i = j; | 
 |     integer.width = sizeof(short); | 
 |   } | 
 |   Arg(unsigned short j) : type(UINT) { | 
 |     integer.i = j; | 
 |     integer.width = sizeof(short); | 
 |   } | 
 |   Arg(signed int j) : type(INT) { | 
 |     integer.i = j; | 
 |     integer.width = sizeof(int); | 
 |   } | 
 |   Arg(unsigned int j) : type(UINT) { | 
 |     integer.i = j; | 
 |     integer.width = sizeof(int); | 
 |   } | 
 |   Arg(signed long j) : type(INT) { | 
 |     integer.i = j; | 
 |     integer.width = sizeof(long); | 
 |   } | 
 |   Arg(unsigned long j) : type(UINT) { | 
 |     integer.i = j; | 
 |     integer.width = sizeof(long); | 
 |   } | 
 |   Arg(signed long long j) : type(INT) { | 
 |     integer.i = j; | 
 |     integer.width = sizeof(long long); | 
 |   } | 
 |   Arg(unsigned long long j) : type(UINT) { | 
 |     integer.i = j; | 
 |     integer.width = sizeof(long long); | 
 |   } | 
 |  | 
 |   // A C-style text string. | 
 |   Arg(const char* s) : str(s), type(STRING) { } | 
 |   Arg(char* s)       : str(s), type(STRING) { } | 
 |  | 
 |   // Any pointer value that can be cast to a "void*". | 
 |   template<class T> Arg(T* p) : ptr((void*)p), type(POINTER) { } | 
 |  | 
 |   union { | 
 |     // An integer-like value. | 
 |     struct { | 
 |       int64_t       i; | 
 |       unsigned char width; | 
 |     } integer; | 
 |  | 
 |     // A C-style text string. | 
 |     const char* str; | 
 |  | 
 |     // A pointer to an arbitrary object. | 
 |     const void* ptr; | 
 |   }; | 
 |   const enum Type type; | 
 | }; | 
 |  | 
 | // This is the internal function that performs the actual formatting of | 
 | // an snprintf()-style format string. | 
 | BASE_EXPORT ssize_t SafeSNPrintf(char* buf, size_t sz, const char* fmt, | 
 |                                  const Arg* args, size_t max_args); | 
 |  | 
 | #if !defined(NDEBUG) | 
 | // In debug builds, allow unit tests to artificially lower the kSSizeMax | 
 | // constant that is used as a hard upper-bound for all buffers. In normal | 
 | // use, this constant should always be std::numeric_limits<ssize_t>::max(). | 
 | BASE_EXPORT void SetSafeSPrintfSSizeMaxForTest(size_t max); | 
 | BASE_EXPORT size_t GetSafeSPrintfSSizeMaxForTest(); | 
 | #endif | 
 |  | 
 | }  // namespace internal | 
 |  | 
 | template<typename... Args> | 
 | ssize_t SafeSNPrintf(char* buf, size_t N, const char* fmt, Args... args) { | 
 |   // Use Arg() object to record type information and then copy arguments to an | 
 |   // array to make it easier to iterate over them. | 
 |   const internal::Arg arg_array[] = { args... }; | 
 |   return internal::SafeSNPrintf(buf, N, fmt, arg_array, sizeof...(args)); | 
 | } | 
 |  | 
 | template<size_t N, typename... Args> | 
 | ssize_t SafeSPrintf(char (&buf)[N], const char* fmt, Args... args) { | 
 |   // Use Arg() object to record type information and then copy arguments to an | 
 |   // array to make it easier to iterate over them. | 
 |   const internal::Arg arg_array[] = { args... }; | 
 |   return internal::SafeSNPrintf(buf, N, fmt, arg_array, sizeof...(args)); | 
 | } | 
 |  | 
 | // Fast-path when we don't actually need to substitute any arguments. | 
 | BASE_EXPORT ssize_t SafeSNPrintf(char* buf, size_t N, const char* fmt); | 
 | template<size_t N> | 
 | inline ssize_t SafeSPrintf(char (&buf)[N], const char* fmt) { | 
 |   return SafeSNPrintf(buf, N, fmt); | 
 | } | 
 |  | 
 | }  // namespace strings | 
 | }  // namespace base | 
 |  | 
 | #endif  // BASE_STRINGS_SAFE_SPRINTF_H_ |