| Index: base/strings/string_number_conversions.h
|
| diff --git a/base/strings/string_number_conversions.h b/base/strings/string_number_conversions.h
|
| index cf1c3b467ddb269bb5a6c4ec61f7325110d83c2d..ee4807cd85c9116535b94cbdacef44f7db99e168 100644
|
| --- a/base/strings/string_number_conversions.h
|
| +++ b/base/strings/string_number_conversions.h
|
| @@ -8,6 +8,11 @@
|
| #include <string>
|
| #include <vector>
|
|
|
| +#if defined(STRING_NUMBER_CONVERSIONS_DETECT_RISKY_CONVERSIONS)
|
| +#include <limits>
|
| +#include <type_traits>
|
| +#endif
|
| +
|
| #include "base/base_export.h"
|
| #include "base/basictypes.h"
|
| #include "base/strings/string16.h"
|
| @@ -29,6 +34,10 @@ namespace base {
|
|
|
| // Number -> string conversions ------------------------------------------------
|
|
|
| +#if defined(STRING_NUMBER_CONVERSIONS_DETECT_RISKY_CONVERSIONS)
|
| +namespace internal {
|
| +#endif
|
| +
|
| BASE_EXPORT std::string IntToString(int value);
|
| BASE_EXPORT string16 IntToString16(int value);
|
|
|
| @@ -48,6 +57,10 @@ BASE_EXPORT string16 SizeTToString16(size_t value);
|
| // locale. If you want to use locale specific formatting, use ICU.
|
| BASE_EXPORT std::string DoubleToString(double value);
|
|
|
| +#if defined(STRING_NUMBER_CONVERSIONS_DETECT_RISKY_CONVERSIONS)
|
| +} // namespace internal
|
| +#endif
|
| +
|
| // String -> number conversions ------------------------------------------------
|
|
|
| // Perform a best-effort conversion of the input string to a numeric type,
|
| @@ -130,6 +143,128 @@ BASE_EXPORT bool HexStringToUInt64(const StringPiece& input, uint64* output);
|
| BASE_EXPORT bool HexStringToBytes(const std::string& input,
|
| std::vector<uint8>* output);
|
|
|
| +// Detection of potentially risky conversions. This is not enabled by default
|
| +// because it has too many false positives.
|
| +//
|
| +// How to use:
|
| +// 1. Define STRING_NUMBER_CONVERSIONS_DETECT_RISKY_CONVERSIONS (probably the
|
| +// easiest way is to make a local modification to this file, but make sure
|
| +// you don't check it in).
|
| +// 2. Compile the code you want to check.
|
| +// 3. You will see errors like "error: temporary of type
|
| +// 'SignedUnsignedMismatch' (aka 'base::ErrorOnUse') has private destructor"
|
| +// 4. Check the actual type of the variable being passed in.
|
| +// 5. Attempt to determine whether the "wrong" conversion function is being used
|
| +// intentionally. Pay particular attention to 32-bit/64-bit issues and
|
| +// cross-platform compatibility.
|
| +// 6. Decide if it would be better to use a different conversion function.
|
| +// 7. If so, make the change, compile it, and test it.
|
| +//
|
| +#if defined(STRING_NUMBER_CONVERSIONS_DETECT_RISKY_CONVERSIONS)
|
| +
|
| +// Enums are weird. They have an "underlying type", but that is
|
| +// implementation-specific (unless explicitly specified). However, the overload
|
| +// resolution order for enums *is* specified in the standard, specifically:
|
| +//
|
| +// """ A prvalue of an unscoped enumeration type whose underlying type is not
|
| +// fixed (7.2) can be converted to a prvalue of the first of the following types
|
| +// that can represent all the values of the enumeration (i.e., the values in the
|
| +// range b min to b max as described in 7.2): int, unsigned int, long int,
|
| +// unsigned long int, long long int, or unsigned long long int. """
|
| +//
|
| +// Since that is portable, decide the correct function to pass an enum to based
|
| +// on overload resolution.
|
| +template <typename T>
|
| +class EnumOverloadOrOriginalType {
|
| + private:
|
| + template <typename T2, bool is_enum>
|
| + struct Impl;
|
| +
|
| + template <typename T2>
|
| + struct Impl<T2, false> {
|
| + typedef T2 type;
|
| + };
|
| +
|
| + template <typename T2>
|
| + struct Impl<T2, true> {
|
| + static int deduce(int);
|
| + static uint32 deduce(uint32);
|
| + static int64 deduce(int64);
|
| + static uint64 deduce(uint64);
|
| +
|
| + typedef decltype(deduce(T2())) type;
|
| + };
|
| +
|
| + public:
|
| + typedef typename Impl<T, std::is_enum<T>::value>::type type;
|
| +};
|
| +
|
| +template <typename ReturnType,
|
| + typename ExpectedType,
|
| + ReturnType(Function)(ExpectedType)>
|
| +struct LooseMatchFunctor {
|
| + constexpr LooseMatchFunctor() {}
|
| +
|
| + template <typename T>
|
| + ReturnType operator()(T value) const {
|
| + static_assert(
|
| + std::is_arithmetic<T>::value || std::is_enum<T>::value,
|
| + "Type passed to numeric conversions must be arithmetic or enum");
|
| + // If T is an enum, then it is the underlying type we are interested in.
|
| + typedef typename EnumOverloadOrOriginalType<T>::type ActualType;
|
| + static_assert(std::is_arithmetic<ActualType>::value,
|
| + "ActualType must be arithmetic");
|
| + static_assert(sizeof(ActualType) <= sizeof(ExpectedType),
|
| + "Silent truncation of larger integer type");
|
| + static_assert(std::is_enum<ActualType>::value ||
|
| + std::numeric_limits<ActualType>::is_signed ==
|
| + std::numeric_limits<ExpectedType>::is_signed,
|
| + "Signed/unsigned mismatch");
|
| + static_assert(std::is_enum<ActualType>::value ||
|
| + std::numeric_limits<ActualType>::is_integer ==
|
| + std::numeric_limits<ExpectedType>::is_integer,
|
| + "Integer/floating point mismatch");
|
| + return Function(value);
|
| + }
|
| +};
|
| +
|
| +template <typename ReturnType,
|
| + typename ExpectedType,
|
| + ReturnType(Function)(ExpectedType)>
|
| +struct ExactMatchFunctor {
|
| + constexpr ExactMatchFunctor() {}
|
| +
|
| + template <typename ActualType>
|
| + ReturnType operator()(ActualType value) const {
|
| + static_assert(std::is_same<ActualType, ExpectedType>::value,
|
| + "Types do not match");
|
| + return Function(value);
|
| + }
|
| +};
|
| +
|
| +#define DEFINE_INT_TO_STRING_FUNCTION(RETURN_TYPE, EXPECTED_TYPE, FUNCTION) \
|
| + constexpr LooseMatchFunctor<RETURN_TYPE, EXPECTED_TYPE, internal::FUNCTION> \
|
| + FUNCTION
|
| +
|
| +#define DEFINE_EXACT_MATCH_INT_TO_STRING_FUNCTION(RETURN_TYPE, EXPECTED_TYPE, \
|
| + FUNCTION) \
|
| + constexpr ExactMatchFunctor<RETURN_TYPE, EXPECTED_TYPE, internal::FUNCTION> \
|
| + FUNCTION
|
| +
|
| +DEFINE_INT_TO_STRING_FUNCTION(std::string, int, IntToString);
|
| +DEFINE_INT_TO_STRING_FUNCTION(string16, int, IntToString16);
|
| +DEFINE_INT_TO_STRING_FUNCTION(std::string, uint32, UintToString);
|
| +DEFINE_INT_TO_STRING_FUNCTION(string16, uint32, UintToString16);
|
| +DEFINE_INT_TO_STRING_FUNCTION(std::string, int64, Int64ToString);
|
| +DEFINE_INT_TO_STRING_FUNCTION(string16, int64, Int64ToString16);
|
| +DEFINE_INT_TO_STRING_FUNCTION(std::string, uint64, Uint64ToString);
|
| +DEFINE_INT_TO_STRING_FUNCTION(string16, uint64, Uint64ToString16);
|
| +DEFINE_EXACT_MATCH_INT_TO_STRING_FUNCTION(std::string, size_t, SizeTToString);
|
| +DEFINE_EXACT_MATCH_INT_TO_STRING_FUNCTION(string16, size_t, SizeTToString16);
|
| +DEFINE_INT_TO_STRING_FUNCTION(std::string, double, DoubleToString);
|
| +
|
| +#endif
|
| +
|
| } // namespace base
|
|
|
| #endif // BASE_STRINGS_STRING_NUMBER_CONVERSIONS_H_
|
|
|