mirror of
https://github.com/google/flatbuffers.git
synced 2026-07-01 16:53:57 +00:00
JSON parser wasn't handling ulong values correctly.
It passed all scalar ints thru a int64_t, which would truncate uint64_t values with the upper bit set. Change-Id: I38fb8c68c911ae44d9863f8e35c2429ca0ab51e5 Tested: on Linux.
This commit is contained in:
@@ -520,7 +520,7 @@ class Parser : public ParserState {
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
FLATBUFFERS_CHECKED_ERROR Error(const std::string &msg);
|
FLATBUFFERS_CHECKED_ERROR Error(const std::string &msg);
|
||||||
FLATBUFFERS_CHECKED_ERROR ParseHexNum(int nibbles, int64_t *val);
|
FLATBUFFERS_CHECKED_ERROR ParseHexNum(int nibbles, uint64_t *val);
|
||||||
FLATBUFFERS_CHECKED_ERROR Next();
|
FLATBUFFERS_CHECKED_ERROR Next();
|
||||||
FLATBUFFERS_CHECKED_ERROR SkipByteOrderMark();
|
FLATBUFFERS_CHECKED_ERROR SkipByteOrderMark();
|
||||||
bool Is(int t);
|
bool Is(int t);
|
||||||
|
|||||||
@@ -95,7 +95,8 @@ inline std::string IntToStringHex(int i, int xdigits) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Portable implementation of strtoll().
|
// Portable implementation of strtoll().
|
||||||
inline int64_t StringToInt(const char *str, char **endptr = nullptr, int base = 10) {
|
inline int64_t StringToInt(const char *str, char **endptr = nullptr,
|
||||||
|
int base = 10) {
|
||||||
#ifdef _MSC_VER
|
#ifdef _MSC_VER
|
||||||
return _strtoi64(str, endptr, base);
|
return _strtoi64(str, endptr, base);
|
||||||
#else
|
#else
|
||||||
@@ -104,7 +105,8 @@ inline int64_t StringToInt(const char *str, char **endptr = nullptr, int base =
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Portable implementation of strtoull().
|
// Portable implementation of strtoull().
|
||||||
inline int64_t StringToUInt(const char *str, char **endptr = nullptr, int base = 10) {
|
inline uint64_t StringToUInt(const char *str, char **endptr = nullptr,
|
||||||
|
int base = 10) {
|
||||||
#ifdef _MSC_VER
|
#ifdef _MSC_VER
|
||||||
return _strtoui64(str, endptr, base);
|
return _strtoui64(str, endptr, base);
|
||||||
#else
|
#else
|
||||||
|
|||||||
@@ -109,6 +109,12 @@ template<typename T> inline CheckedError atot(const char *s, Parser &parser,
|
|||||||
*val = (T)i;
|
*val = (T)i;
|
||||||
return NoError();
|
return NoError();
|
||||||
}
|
}
|
||||||
|
template<> inline CheckedError atot<uint64_t>(const char *s, Parser &parser,
|
||||||
|
uint64_t *val) {
|
||||||
|
(void)parser;
|
||||||
|
*val = StringToUInt(s);
|
||||||
|
return NoError();
|
||||||
|
}
|
||||||
template<> inline CheckedError atot<bool>(const char *s, Parser &parser,
|
template<> inline CheckedError atot<bool>(const char *s, Parser &parser,
|
||||||
bool *val) {
|
bool *val) {
|
||||||
(void)parser;
|
(void)parser;
|
||||||
@@ -213,7 +219,7 @@ std::string Parser::TokenToStringId(int t) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Parses exactly nibbles worth of hex digits into a number, or error.
|
// Parses exactly nibbles worth of hex digits into a number, or error.
|
||||||
CheckedError Parser::ParseHexNum(int nibbles, int64_t *val) {
|
CheckedError Parser::ParseHexNum(int nibbles, uint64_t *val) {
|
||||||
for (int i = 0; i < nibbles; i++)
|
for (int i = 0; i < nibbles; i++)
|
||||||
if (!isxdigit(static_cast<const unsigned char>(cursor_[i])))
|
if (!isxdigit(static_cast<const unsigned char>(cursor_[i])))
|
||||||
return Error("escape code must be followed by " + NumToString(nibbles) +
|
return Error("escape code must be followed by " + NumToString(nibbles) +
|
||||||
@@ -280,14 +286,14 @@ CheckedError Parser::Next() {
|
|||||||
case '/': attribute_ += '/'; cursor_++; break;
|
case '/': attribute_ += '/'; cursor_++; break;
|
||||||
case 'x': { // Not in the JSON standard
|
case 'x': { // Not in the JSON standard
|
||||||
cursor_++;
|
cursor_++;
|
||||||
int64_t val;
|
uint64_t val;
|
||||||
ECHECK(ParseHexNum(2, &val));
|
ECHECK(ParseHexNum(2, &val));
|
||||||
attribute_ += static_cast<char>(val);
|
attribute_ += static_cast<char>(val);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case 'u': {
|
case 'u': {
|
||||||
cursor_++;
|
cursor_++;
|
||||||
int64_t val;
|
uint64_t val;
|
||||||
ECHECK(ParseHexNum(4, &val));
|
ECHECK(ParseHexNum(4, &val));
|
||||||
if (val >= 0xD800 && val <= 0xDBFF) {
|
if (val >= 0xD800 && val <= 0xDBFF) {
|
||||||
if (unicode_high_surrogate != -1) {
|
if (unicode_high_surrogate != -1) {
|
||||||
@@ -442,7 +448,8 @@ CheckedError Parser::Next() {
|
|||||||
return NoError();
|
return NoError();
|
||||||
} else if (isdigit(static_cast<unsigned char>(c)) || c == '-') {
|
} else if (isdigit(static_cast<unsigned char>(c)) || c == '-') {
|
||||||
const char *start = cursor_ - 1;
|
const char *start = cursor_ - 1;
|
||||||
if (c == '-' && *cursor_ == '0' && (cursor_[1] == 'x' || cursor_[1] == 'X')) {
|
if (c == '-' && *cursor_ == '0' &&
|
||||||
|
(cursor_[1] == 'x' || cursor_[1] == 'X')) {
|
||||||
++start;
|
++start;
|
||||||
++cursor_;
|
++cursor_;
|
||||||
attribute_.append(&c, &c + 1);
|
attribute_.append(&c, &c + 1);
|
||||||
@@ -452,7 +459,8 @@ CheckedError Parser::Next() {
|
|||||||
cursor_++;
|
cursor_++;
|
||||||
while (isxdigit(static_cast<unsigned char>(*cursor_))) cursor_++;
|
while (isxdigit(static_cast<unsigned char>(*cursor_))) cursor_++;
|
||||||
attribute_.append(start + 2, cursor_);
|
attribute_.append(start + 2, cursor_);
|
||||||
attribute_ = NumToString(StringToUInt(attribute_.c_str(), nullptr, 16));
|
attribute_ = NumToString(static_cast<int64_t>(
|
||||||
|
StringToUInt(attribute_.c_str(), nullptr, 16)));
|
||||||
token_ = kTokenIntegerConstant;
|
token_ = kTokenIntegerConstant;
|
||||||
return NoError();
|
return NoError();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -994,14 +994,13 @@ template<typename T> T TestValue(const char *json, const char *type_name) {
|
|||||||
flatbuffers::Parser parser;
|
flatbuffers::Parser parser;
|
||||||
|
|
||||||
// Simple schema.
|
// Simple schema.
|
||||||
TEST_EQ(parser.Parse(std::string("table X { Y:" + std::string(type_name) + "; } root_type X;").c_str()), true);
|
TEST_EQ(parser.Parse(std::string("table X { Y:" + std::string(type_name) +
|
||||||
|
"; } root_type X;").c_str()), true);
|
||||||
|
|
||||||
TEST_EQ(parser.Parse(json), true);
|
TEST_EQ(parser.Parse(json), true);
|
||||||
auto root = flatbuffers::GetRoot<T>(parser.builder_.GetBufferPointer());
|
auto root = flatbuffers::GetRoot<flatbuffers::Table>(
|
||||||
// root will point to the table, which is a 32bit vtable offset followed
|
parser.builder_.GetBufferPointer());
|
||||||
// by a float:
|
return root->GetField<T>(flatbuffers::FieldIndexToOffset(0), 0);
|
||||||
TEST_EQ(sizeof(flatbuffers::soffset_t), 4); // Test assumes 32bit offsets
|
|
||||||
return root[1];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool FloatCompare(float a, float b) { return fabs(a - b) < 0.001; }
|
bool FloatCompare(float a, float b) { return fabs(a - b) < 0.001; }
|
||||||
@@ -1009,13 +1008,19 @@ bool FloatCompare(float a, float b) { return fabs(a - b) < 0.001; }
|
|||||||
// Additional parser testing not covered elsewhere.
|
// Additional parser testing not covered elsewhere.
|
||||||
void ValueTest() {
|
void ValueTest() {
|
||||||
// Test scientific notation numbers.
|
// Test scientific notation numbers.
|
||||||
TEST_EQ(FloatCompare(TestValue<float>("{ Y:0.0314159e+2 }","float"), (float)3.14159), true);
|
TEST_EQ(FloatCompare(TestValue<float>("{ Y:0.0314159e+2 }","float"),
|
||||||
|
(float)3.14159), true);
|
||||||
|
|
||||||
// Test conversion functions.
|
// Test conversion functions.
|
||||||
TEST_EQ(FloatCompare(TestValue<float>("{ Y:cos(rad(180)) }","float"), -1), true);
|
TEST_EQ(FloatCompare(TestValue<float>("{ Y:cos(rad(180)) }","float"), -1),
|
||||||
|
true);
|
||||||
|
|
||||||
// Test negative hex constant.
|
// Test negative hex constant.
|
||||||
TEST_EQ(TestValue<int>("{ Y:-0x80 }","int") == -128, true);
|
TEST_EQ(TestValue<int>("{ Y:-0x80 }","int"), -128);
|
||||||
|
|
||||||
|
// Make sure we do unsigned 64bit correctly.
|
||||||
|
TEST_EQ(TestValue<uint64_t>("{ Y:12335089644688340133 }","ulong"),
|
||||||
|
12335089644688340133ULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
void EnumStringsTest() {
|
void EnumStringsTest() {
|
||||||
|
|||||||
Reference in New Issue
Block a user