mirror of
https://github.com/chromium/crashpad.git
synced 2024-12-26 23:01:05 +08:00
Switch all string-number conversion to use fundamental types, and add long to the list.
Change-Id: I9244df09415f9d46262e2b8d04b64d7c4f786436 Reviewed-on: https://chromium-review.googlesource.com/c/crashpad/crashpad/+/1565287 Commit-Queue: Eric Astor <epastor@google.com> Reviewed-by: Mark Mentovai <mark@chromium.org>
This commit is contained in:
parent
ad49fcfad6
commit
e50676dcf2
@ -97,15 +97,34 @@ struct StringToUnsignedIntTraits
|
||||
}
|
||||
};
|
||||
|
||||
struct StringToInt64Traits
|
||||
: public StringToSignedIntegerTraits<int64_t, int64_t> {
|
||||
struct StringToLongTraits
|
||||
: public StringToSignedIntegerTraits<long, long long> {
|
||||
static LongType Convert(const char* str, char** end, int base) {
|
||||
return strtoll(str, end, base);
|
||||
}
|
||||
};
|
||||
|
||||
struct StringToUnsignedInt64Traits
|
||||
: public StringToUnsignedIntegerTraits<uint64_t, uint64_t> {
|
||||
struct StringToUnsignedLongTraits
|
||||
: public StringToUnsignedIntegerTraits<unsigned long, unsigned long long> {
|
||||
static LongType Convert(const char* str, char** end, int base) {
|
||||
if (str[0] == '-') {
|
||||
*end = const_cast<char*>(str);
|
||||
return 0;
|
||||
}
|
||||
return strtoull(str, end, base);
|
||||
}
|
||||
};
|
||||
|
||||
struct StringToLongLongTraits
|
||||
: public StringToSignedIntegerTraits<long long, long long> {
|
||||
static LongType Convert(const char* str, char** end, int base) {
|
||||
return strtoll(str, end, base);
|
||||
}
|
||||
};
|
||||
|
||||
struct StringToUnsignedLongLongTraits
|
||||
: public StringToUnsignedIntegerTraits<unsigned long long,
|
||||
unsigned long long> {
|
||||
static LongType Convert(const char* str, char** end, int base) {
|
||||
if (str[0] == '-') {
|
||||
*end = const_cast<char*>(str);
|
||||
@ -136,7 +155,7 @@ bool StringToIntegerInternal(const std::string& string,
|
||||
end != string.data() + string.length()) {
|
||||
return false;
|
||||
}
|
||||
*number = result;
|
||||
*number = static_cast<IntType>(result);
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -152,12 +171,21 @@ bool StringToNumber(const std::string& string, unsigned int* number) {
|
||||
return StringToIntegerInternal<StringToUnsignedIntTraits>(string, number);
|
||||
}
|
||||
|
||||
bool StringToNumber(const std::string& string, int64_t* number) {
|
||||
return StringToIntegerInternal<StringToInt64Traits>(string, number);
|
||||
bool StringToNumber(const std::string& string, long* number) {
|
||||
return StringToIntegerInternal<StringToLongTraits>(string, number);
|
||||
}
|
||||
|
||||
bool StringToNumber(const std::string& string, uint64_t* number) {
|
||||
return StringToIntegerInternal<StringToUnsignedInt64Traits>(string, number);
|
||||
bool StringToNumber(const std::string& string, unsigned long* number) {
|
||||
return StringToIntegerInternal<StringToUnsignedLongTraits>(string, number);
|
||||
}
|
||||
|
||||
bool StringToNumber(const std::string& string, long long* number) {
|
||||
return StringToIntegerInternal<StringToLongLongTraits>(string, number);
|
||||
}
|
||||
|
||||
bool StringToNumber(const std::string& string, unsigned long long* number) {
|
||||
return StringToIntegerInternal<StringToUnsignedLongLongTraits>(string,
|
||||
number);
|
||||
}
|
||||
|
||||
} // namespace crashpad
|
||||
|
@ -56,8 +56,10 @@ namespace crashpad {
|
||||
//! where such prefix recognition is desirable.
|
||||
bool StringToNumber(const std::string& string, int* number);
|
||||
bool StringToNumber(const std::string& string, unsigned int* number);
|
||||
bool StringToNumber(const std::string& string, int64_t* number);
|
||||
bool StringToNumber(const std::string& string, uint64_t* number);
|
||||
bool StringToNumber(const std::string& string, long* number);
|
||||
bool StringToNumber(const std::string& string, unsigned long* number);
|
||||
bool StringToNumber(const std::string& string, long long* number);
|
||||
bool StringToNumber(const std::string& string, unsigned long long* number);
|
||||
//! \}
|
||||
|
||||
} // namespace crashpad
|
||||
|
@ -16,30 +16,39 @@
|
||||
|
||||
#include <sys/types.h>
|
||||
|
||||
#include <array>
|
||||
#include <limits>
|
||||
#include <type_traits>
|
||||
|
||||
#include "base/stl_util.h"
|
||||
#include "gtest/gtest.h"
|
||||
|
||||
namespace crashpad {
|
||||
namespace test {
|
||||
namespace {
|
||||
#define STRINGIFY(a) STR(a)
|
||||
#define STR(a) #a
|
||||
|
||||
TEST(StringNumberConversion, StringToInt) {
|
||||
static constexpr struct {
|
||||
const char* string;
|
||||
bool valid;
|
||||
int value;
|
||||
} kTestData[] = {
|
||||
template <typename TValueType>
|
||||
struct TestSpecification {
|
||||
const char* string;
|
||||
bool valid;
|
||||
TValueType value;
|
||||
};
|
||||
|
||||
// Signed 32-bit test data
|
||||
template <typename TIntType,
|
||||
typename std::enable_if<std::is_integral<TIntType>::value &&
|
||||
std::is_signed<TIntType>::value &&
|
||||
(sizeof(TIntType) == 4)>::type* = nullptr>
|
||||
static constexpr std::array<TestSpecification<TIntType>, 61> kTestDataFunc() {
|
||||
return {{
|
||||
{"", false, 0},
|
||||
{"0", true, 0},
|
||||
{"1", true, 1},
|
||||
{"2147483647", true, std::numeric_limits<int>::max()},
|
||||
{"2147483647", true, std::numeric_limits<TIntType>::max()},
|
||||
{"2147483648", false, 0},
|
||||
{"4294967295", false, 0},
|
||||
{"4294967296", false, 0},
|
||||
{"-1", true, -1},
|
||||
{"-2147483648", true, std::numeric_limits<int>::min()},
|
||||
{"-2147483648", true, std::numeric_limits<TIntType>::min()},
|
||||
{"-2147483649", false, 0},
|
||||
{"00", true, 0},
|
||||
{"01", true, 1},
|
||||
@ -50,12 +59,12 @@ TEST(StringNumberConversion, StringToInt) {
|
||||
{"+0x20", true, 32},
|
||||
{"0xf", true, 15},
|
||||
{"0xg", false, 0},
|
||||
{"0x7fffffff", true, std::numeric_limits<int>::max()},
|
||||
{"0x7FfFfFfF", true, std::numeric_limits<int>::max()},
|
||||
{"0x7fffffff", true, std::numeric_limits<TIntType>::max()},
|
||||
{"0x7FfFfFfF", true, std::numeric_limits<TIntType>::max()},
|
||||
{"0x80000000", false, 0},
|
||||
{"0xFFFFFFFF", false, 0},
|
||||
{"-0x7fffffff", true, -2147483647},
|
||||
{"-0x80000000", true, std::numeric_limits<int>::min()},
|
||||
{"-0x80000000", true, std::numeric_limits<TIntType>::min()},
|
||||
{"-0x80000001", false, 0},
|
||||
{"-0xffffffff", false, 0},
|
||||
{"0x100000000", false, 0},
|
||||
@ -92,45 +101,22 @@ TEST(StringNumberConversion, StringToInt) {
|
||||
{"9223372036854775809", false, 0},
|
||||
{"18446744073709551615", false, 0},
|
||||
{"18446744073709551616", false, 0},
|
||||
};
|
||||
|
||||
for (size_t index = 0; index < base::size(kTestData); ++index) {
|
||||
int value;
|
||||
bool valid = StringToNumber(kTestData[index].string, &value);
|
||||
if (kTestData[index].valid) {
|
||||
EXPECT_TRUE(valid) << "index " << index << ", string "
|
||||
<< kTestData[index].string;
|
||||
if (valid) {
|
||||
EXPECT_EQ(value, kTestData[index].value)
|
||||
<< "index " << index << ", string " << kTestData[index].string;
|
||||
}
|
||||
} else {
|
||||
EXPECT_FALSE(valid) << "index " << index << ", string "
|
||||
<< kTestData[index].string << ", value " << value;
|
||||
}
|
||||
}
|
||||
|
||||
// Ensure that embedded NUL characters are treated as bad input. The string
|
||||
// is split to avoid MSVC warning:
|
||||
// "decimal digit terminates octal escape sequence".
|
||||
static constexpr char input[] = "6\000" "6";
|
||||
std::string input_string(input, base::size(input) - 1);
|
||||
int output;
|
||||
EXPECT_FALSE(StringToNumber(input_string, &output));
|
||||
}};
|
||||
}
|
||||
|
||||
TEST(StringNumberConversion, StringToUnsignedInt) {
|
||||
static constexpr struct {
|
||||
const char* string;
|
||||
bool valid;
|
||||
unsigned int value;
|
||||
} kTestData[] = {
|
||||
// Unsigned 32-bit test data
|
||||
template <typename TIntType,
|
||||
typename std::enable_if<std::is_integral<TIntType>::value &&
|
||||
!std::is_signed<TIntType>::value &&
|
||||
(sizeof(TIntType) == 4)>::type* = nullptr>
|
||||
static constexpr std::array<TestSpecification<TIntType>, 61> kTestDataFunc() {
|
||||
return {{
|
||||
{"", false, 0},
|
||||
{"0", true, 0},
|
||||
{"1", true, 1},
|
||||
{"2147483647", true, 2147483647},
|
||||
{"2147483648", true, 2147483648},
|
||||
{"4294967295", true, std::numeric_limits<unsigned int>::max()},
|
||||
{"4294967295", true, std::numeric_limits<TIntType>::max()},
|
||||
{"4294967296", false, 0},
|
||||
{"-1", false, 0},
|
||||
{"-2147483648", false, 0},
|
||||
@ -186,9 +172,121 @@ TEST(StringNumberConversion, StringToUnsignedInt) {
|
||||
{"9223372036854775809", false, 0},
|
||||
{"18446744073709551615", false, 0},
|
||||
{"18446744073709551616", false, 0},
|
||||
};
|
||||
}};
|
||||
}
|
||||
|
||||
for (size_t index = 0; index < base::size(kTestData); ++index) {
|
||||
// Signed 64-bit test data
|
||||
template <typename TIntType,
|
||||
typename std::enable_if<std::is_integral<TIntType>::value &&
|
||||
std::is_signed<TIntType>::value &&
|
||||
(sizeof(TIntType) == 8)>::type* = nullptr>
|
||||
static constexpr std::array<TestSpecification<TIntType>, 24> kTestDataFunc() {
|
||||
return {{
|
||||
{"", false, 0},
|
||||
{"0", true, 0},
|
||||
{"1", true, 1},
|
||||
{"2147483647", true, 2147483647},
|
||||
{"2147483648", true, 2147483648},
|
||||
{"4294967295", true, 4294967295},
|
||||
{"4294967296", true, 4294967296},
|
||||
{"9223372036854775807", true, std::numeric_limits<TIntType>::max()},
|
||||
{"9223372036854775808", false, 0},
|
||||
{"18446744073709551615", false, 0},
|
||||
{"18446744073709551616", false, 0},
|
||||
{"-1", true, -1},
|
||||
{"-2147483648", true, INT64_C(-2147483648)},
|
||||
{"-2147483649", true, INT64_C(-2147483649)},
|
||||
{"-9223372036854775808", true, std::numeric_limits<TIntType>::min()},
|
||||
{"-9223372036854775809", false, 0},
|
||||
{"0x7fffffffffffffff", true, std::numeric_limits<TIntType>::max()},
|
||||
{"0x8000000000000000", false, 0},
|
||||
{"0xffffffffffffffff", false, 0},
|
||||
{"0x10000000000000000", false, 0},
|
||||
{"-0x7fffffffffffffff", true, -9223372036854775807},
|
||||
{"-0x8000000000000000", true, std::numeric_limits<TIntType>::min()},
|
||||
{"-0x8000000000000001", false, 0},
|
||||
{"0x7Fffffffffffffff", true, std::numeric_limits<TIntType>::max()},
|
||||
}};
|
||||
}
|
||||
|
||||
// Unsigned 64-bit test data
|
||||
template <typename TIntType,
|
||||
typename std::enable_if<std::is_integral<TIntType>::value &&
|
||||
!std::is_signed<TIntType>::value &&
|
||||
(sizeof(TIntType) == 8)>::type* = nullptr>
|
||||
static constexpr std::array<TestSpecification<TIntType>, 25> kTestDataFunc() {
|
||||
return {{
|
||||
{"", false, 0},
|
||||
{"0", true, 0},
|
||||
{"1", true, 1},
|
||||
{"2147483647", true, 2147483647},
|
||||
{"2147483648", true, 2147483648},
|
||||
{"4294967295", true, 4294967295},
|
||||
{"4294967296", true, 4294967296},
|
||||
{"9223372036854775807", true, 9223372036854775807},
|
||||
{"9223372036854775808", true, 9223372036854775808u},
|
||||
{"18446744073709551615", true, std::numeric_limits<TIntType>::max()},
|
||||
{"18446744073709551616", false, 0},
|
||||
{"-1", false, 0},
|
||||
{"-2147483648", false, 0},
|
||||
{"-2147483649", false, 0},
|
||||
{"-2147483648", false, 0},
|
||||
{"-9223372036854775808", false, 0},
|
||||
{"-9223372036854775809", false, 0},
|
||||
{"0x7fffffffffffffff", true, 9223372036854775807},
|
||||
{"0x8000000000000000", true, 9223372036854775808u},
|
||||
{"0xffffffffffffffff", true, std::numeric_limits<TIntType>::max()},
|
||||
{"0x10000000000000000", false, 0},
|
||||
{"-0x7fffffffffffffff", false, 0},
|
||||
{"-0x8000000000000000", false, 0},
|
||||
{"-0x8000000000000001", false, 0},
|
||||
{"0xFfffffffffffffff", true, std::numeric_limits<TIntType>::max()},
|
||||
}};
|
||||
}
|
||||
|
||||
// This string is split to avoid MSVC warning:
|
||||
// "decimal digit terminates octal escape sequence".
|
||||
static constexpr char kEmbeddedNullInputRaw[] = "6\000" "6";
|
||||
|
||||
namespace crashpad {
|
||||
namespace test {
|
||||
namespace {
|
||||
|
||||
TEST(StringNumberConversion, StringToInt) {
|
||||
static_assert(sizeof(int) == 4, "Test only configured for 32-bit int.");
|
||||
static constexpr auto kTestData = kTestDataFunc<int>();
|
||||
|
||||
for (size_t index = 0; index < kTestData.size(); ++index) {
|
||||
int value;
|
||||
bool valid = StringToNumber(kTestData[index].string, &value);
|
||||
if (kTestData[index].valid) {
|
||||
EXPECT_TRUE(valid) << "index " << index << ", string "
|
||||
<< kTestData[index].string;
|
||||
if (valid) {
|
||||
EXPECT_EQ(value, kTestData[index].value)
|
||||
<< "index " << index << ", string " << kTestData[index].string;
|
||||
}
|
||||
} else {
|
||||
EXPECT_FALSE(valid) << "index " << index << ", string "
|
||||
<< kTestData[index].string << ", value " << value;
|
||||
}
|
||||
}
|
||||
|
||||
// Ensure that embedded NUL characters are treated as bad input. The string
|
||||
// is split to avoid MSVC warning:
|
||||
// "decimal digit terminates octal escape sequence".
|
||||
int output;
|
||||
std::string kEmbeddedNullInput(kEmbeddedNullInputRaw,
|
||||
base::size(kEmbeddedNullInputRaw) - 1);
|
||||
EXPECT_FALSE(StringToNumber(kEmbeddedNullInput, &output));
|
||||
}
|
||||
|
||||
TEST(StringNumberConversion, StringToUnsignedInt) {
|
||||
static_assert(sizeof(unsigned int) == 4,
|
||||
"Test only configured for 32-bit unsigned int.");
|
||||
static constexpr auto kTestData = kTestDataFunc<unsigned int>();
|
||||
|
||||
for (size_t index = 0; index < kTestData.size(); ++index) {
|
||||
unsigned int value;
|
||||
bool valid = StringToNumber(kTestData[index].string, &value);
|
||||
if (kTestData[index].valid) {
|
||||
@ -207,46 +305,20 @@ TEST(StringNumberConversion, StringToUnsignedInt) {
|
||||
// Ensure that embedded NUL characters are treated as bad input. The string
|
||||
// is split to avoid MSVC warning:
|
||||
// "decimal digit terminates octal escape sequence".
|
||||
static constexpr char input[] = "6\000" "6";
|
||||
std::string input_string(input, base::size(input) - 1);
|
||||
unsigned int output;
|
||||
EXPECT_FALSE(StringToNumber(input_string, &output));
|
||||
std::string kEmbeddedNullInput(kEmbeddedNullInputRaw,
|
||||
base::size(kEmbeddedNullInputRaw) - 1);
|
||||
EXPECT_FALSE(StringToNumber(kEmbeddedNullInput, &output));
|
||||
}
|
||||
|
||||
TEST(StringNumberConversion, StringToInt64) {
|
||||
static constexpr struct {
|
||||
const char* string;
|
||||
bool valid;
|
||||
int64_t value;
|
||||
} kTestData[] = {
|
||||
{"", false, 0},
|
||||
{"0", true, 0},
|
||||
{"1", true, 1},
|
||||
{"2147483647", true, 2147483647},
|
||||
{"2147483648", true, 2147483648},
|
||||
{"4294967295", true, 4294967295},
|
||||
{"4294967296", true, 4294967296},
|
||||
{"9223372036854775807", true, std::numeric_limits<int64_t>::max()},
|
||||
{"9223372036854775808", false, 0},
|
||||
{"18446744073709551615", false, 0},
|
||||
{"18446744073709551616", false, 0},
|
||||
{"-1", true, -1},
|
||||
{"-2147483648", true, INT64_C(-2147483648)},
|
||||
{"-2147483649", true, INT64_C(-2147483649)},
|
||||
{"-9223372036854775808", true, std::numeric_limits<int64_t>::min()},
|
||||
{"-9223372036854775809", false, 0},
|
||||
{"0x7fffffffffffffff", true, std::numeric_limits<int64_t>::max()},
|
||||
{"0x8000000000000000", false, 0},
|
||||
{"0xffffffffffffffff", false, 0},
|
||||
{"0x10000000000000000", false, 0},
|
||||
{"-0x7fffffffffffffff", true, -9223372036854775807},
|
||||
{"-0x8000000000000000", true, std::numeric_limits<int64_t>::min()},
|
||||
{"-0x8000000000000001", false, 0},
|
||||
{"0x7Fffffffffffffff", true, std::numeric_limits<int64_t>::max()},
|
||||
};
|
||||
TEST(StringNumberConversion, StringToLong) {
|
||||
static_assert(
|
||||
sizeof(long) == 4 || sizeof(long) == 8,
|
||||
"Test not configured for " STRINGIFY(__SIZEOF_LONG__) "-byte long");
|
||||
static constexpr auto kTestData = kTestDataFunc<long>();
|
||||
|
||||
for (size_t index = 0; index < base::size(kTestData); ++index) {
|
||||
int64_t value;
|
||||
for (size_t index = 0; index < kTestData.size(); ++index) {
|
||||
long value;
|
||||
bool valid = StringToNumber(kTestData[index].string, &value);
|
||||
if (kTestData[index].valid) {
|
||||
EXPECT_TRUE(valid) << "index " << index << ", string "
|
||||
@ -262,41 +334,58 @@ TEST(StringNumberConversion, StringToInt64) {
|
||||
}
|
||||
}
|
||||
|
||||
TEST(StringNumberConversion, StringToUnsignedInt64) {
|
||||
static constexpr struct {
|
||||
const char* string;
|
||||
bool valid;
|
||||
uint64_t value;
|
||||
} kTestData[] = {
|
||||
{"", false, 0},
|
||||
{"0", true, 0},
|
||||
{"1", true, 1},
|
||||
{"2147483647", true, 2147483647},
|
||||
{"2147483648", true, 2147483648},
|
||||
{"4294967295", true, 4294967295},
|
||||
{"4294967296", true, 4294967296},
|
||||
{"9223372036854775807", true, 9223372036854775807},
|
||||
{"9223372036854775808", true, 9223372036854775808u},
|
||||
{"18446744073709551615", true, std::numeric_limits<uint64_t>::max()},
|
||||
{"18446744073709551616", false, 0},
|
||||
{"-1", false, 0},
|
||||
{"-2147483648", false, 0},
|
||||
{"-2147483649", false, 0},
|
||||
{"-2147483648", false, 0},
|
||||
{"-9223372036854775808", false, 0},
|
||||
{"-9223372036854775809", false, 0},
|
||||
{"0x7fffffffffffffff", true, 9223372036854775807},
|
||||
{"0x8000000000000000", true, 9223372036854775808u},
|
||||
{"0xffffffffffffffff", true, std::numeric_limits<uint64_t>::max()},
|
||||
{"0x10000000000000000", false, 0},
|
||||
{"-0x7fffffffffffffff", false, 0},
|
||||
{"-0x8000000000000000", false, 0},
|
||||
{"-0x8000000000000001", false, 0},
|
||||
{"0xFfffffffffffffff", true, std::numeric_limits<uint64_t>::max()},
|
||||
};
|
||||
TEST(StringNumberConversion, StringToUnsignedLong) {
|
||||
static_assert(
|
||||
sizeof(long) == 4 || sizeof(long) == 8,
|
||||
"Test not configured for " STRINGIFY(__SIZEOF_LONG__) "-byte long");
|
||||
static constexpr auto kTestData = kTestDataFunc<unsigned long>();
|
||||
|
||||
for (size_t index = 0; index < base::size(kTestData); ++index) {
|
||||
uint64_t value;
|
||||
for (size_t index = 0; index < kTestData.size(); ++index) {
|
||||
unsigned long value;
|
||||
bool valid = StringToNumber(kTestData[index].string, &value);
|
||||
if (kTestData[index].valid) {
|
||||
EXPECT_TRUE(valid) << "index " << index << ", string "
|
||||
<< kTestData[index].string;
|
||||
if (valid) {
|
||||
EXPECT_EQ(value, kTestData[index].value)
|
||||
<< "index " << index << ", string " << kTestData[index].string;
|
||||
}
|
||||
} else {
|
||||
EXPECT_FALSE(valid) << "index " << index << ", string "
|
||||
<< kTestData[index].string << ", value " << value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TEST(StringNumberConversion, StringToLongLong) {
|
||||
static_assert(sizeof(long long) == 8,
|
||||
"Test only configured for 64-bit long long.");
|
||||
static constexpr auto kTestData = kTestDataFunc<long long>();
|
||||
|
||||
for (size_t index = 0; index < kTestData.size(); ++index) {
|
||||
long long value;
|
||||
bool valid = StringToNumber(kTestData[index].string, &value);
|
||||
if (kTestData[index].valid) {
|
||||
EXPECT_TRUE(valid) << "index " << index << ", string "
|
||||
<< kTestData[index].string;
|
||||
if (valid) {
|
||||
EXPECT_EQ(value, kTestData[index].value)
|
||||
<< "index " << index << ", string " << kTestData[index].string;
|
||||
}
|
||||
} else {
|
||||
EXPECT_FALSE(valid) << "index " << index << ", string "
|
||||
<< kTestData[index].string << ", value " << value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TEST(StringNumberConversion, StringToUnsignedLongLong) {
|
||||
static_assert(sizeof(unsigned long long) == 8,
|
||||
"Test only configured for 64-bit unsigned long long.");
|
||||
static constexpr auto kTestData = kTestDataFunc<unsigned long long>();
|
||||
|
||||
for (size_t index = 0; index < kTestData.size(); ++index) {
|
||||
unsigned long long value;
|
||||
bool valid = StringToNumber(kTestData[index].string, &value);
|
||||
if (kTestData[index].valid) {
|
||||
EXPECT_TRUE(valid) << "index " << index << ", string "
|
||||
|
Loading…
x
Reference in New Issue
Block a user