diff options
author | Wouter van Oortmerssen <aardappel@gmail.com> | 2017-01-30 17:07:55 -0800 |
---|---|---|
committer | Wouter van Oortmerssen <aardappel@gmail.com> | 2017-02-01 14:18:28 -0800 |
commit | 29574282a283ddc7904d096d27b783b794da7e91 (patch) | |
tree | 5baeccd9063df82d9ef31cc6c2bdd8983babd6f2 | |
parent | 2dd6ba57d132d34172077b637b532e21aa6dda8a (diff) | |
download | flatbuffers-29574282a283ddc7904d096d27b783b794da7e91.tar.gz flatbuffers-29574282a283ddc7904d096d27b783b794da7e91.tar.bz2 flatbuffers-29574282a283ddc7904d096d27b783b794da7e91.zip |
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.
-rw-r--r-- | include/flatbuffers/idl.h | 2 | ||||
-rw-r--r-- | include/flatbuffers/util.h | 6 | ||||
-rw-r--r-- | src/idl_parser.cpp | 18 | ||||
-rw-r--r-- | tests/test.cpp | 29 |
4 files changed, 35 insertions, 20 deletions
diff --git a/include/flatbuffers/idl.h b/include/flatbuffers/idl.h index 898b4104..0956d187 100644 --- a/include/flatbuffers/idl.h +++ b/include/flatbuffers/idl.h @@ -520,7 +520,7 @@ class Parser : public ParserState { private: 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 SkipByteOrderMark(); bool Is(int t); diff --git a/include/flatbuffers/util.h b/include/flatbuffers/util.h index c6755ab8..2bd0ae08 100644 --- a/include/flatbuffers/util.h +++ b/include/flatbuffers/util.h @@ -95,7 +95,8 @@ inline std::string IntToStringHex(int i, int xdigits) { } // 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 return _strtoi64(str, endptr, base); #else @@ -104,7 +105,8 @@ inline int64_t StringToInt(const char *str, char **endptr = nullptr, int base = } // 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 return _strtoui64(str, endptr, base); #else diff --git a/src/idl_parser.cpp b/src/idl_parser.cpp index 5974d044..454abd30 100644 --- a/src/idl_parser.cpp +++ b/src/idl_parser.cpp @@ -109,6 +109,12 @@ template<typename T> inline CheckedError atot(const char *s, Parser &parser, *val = (T)i; 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, bool *val) { (void)parser; @@ -213,7 +219,7 @@ std::string Parser::TokenToStringId(int t) { } // 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++) if (!isxdigit(static_cast<const unsigned char>(cursor_[i]))) return Error("escape code must be followed by " + NumToString(nibbles) + @@ -280,14 +286,14 @@ CheckedError Parser::Next() { case '/': attribute_ += '/'; cursor_++; break; case 'x': { // Not in the JSON standard cursor_++; - int64_t val; + uint64_t val; ECHECK(ParseHexNum(2, &val)); attribute_ += static_cast<char>(val); break; } case 'u': { cursor_++; - int64_t val; + uint64_t val; ECHECK(ParseHexNum(4, &val)); if (val >= 0xD800 && val <= 0xDBFF) { if (unicode_high_surrogate != -1) { @@ -442,7 +448,8 @@ CheckedError Parser::Next() { return NoError(); } else if (isdigit(static_cast<unsigned char>(c)) || c == '-') { 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; ++cursor_; attribute_.append(&c, &c + 1); @@ -452,7 +459,8 @@ CheckedError Parser::Next() { cursor_++; while (isxdigit(static_cast<unsigned char>(*cursor_))) 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; return NoError(); } diff --git a/tests/test.cpp b/tests/test.cpp index dc850727..34841047 100644 --- a/tests/test.cpp +++ b/tests/test.cpp @@ -491,7 +491,7 @@ void ReflectionTest(uint8_t *flatbuf, size_t length) { TEST_NOTNULL(pos_table_ptr); TEST_EQ_STR(pos_table_ptr->name()->c_str(), "MyGame.Example.Vec3"); - + // Now use it to dynamically access a buffer. auto &root = *flatbuffers::GetAnyRoot(flatbuf); @@ -607,11 +607,11 @@ void ReflectionTest(uint8_t *flatbuf, size_t length) { reinterpret_cast<const uint8_t *>(resizingbuf.data()), resizingbuf.size()); TEST_EQ(VerifyMonsterBuffer(resize_verifier), true); - + // Test buffer is valid using reflection as well TEST_EQ(flatbuffers::Verify(schema, *schema.root_table(), resizingbuf.data(), resizingbuf.size()), true); - + // As an additional test, also set it on the name field. // Note: unlike the name change above, this just overwrites the offset, // rather than changing the string in-place. @@ -994,14 +994,13 @@ template<typename T> T TestValue(const char *json, const char *type_name) { flatbuffers::Parser parser; // 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); - auto root = flatbuffers::GetRoot<T>(parser.builder_.GetBufferPointer()); - // root will point to the table, which is a 32bit vtable offset followed - // by a float: - TEST_EQ(sizeof(flatbuffers::soffset_t), 4); // Test assumes 32bit offsets - return root[1]; + auto root = flatbuffers::GetRoot<flatbuffers::Table>( + parser.builder_.GetBufferPointer()); + return root->GetField<T>(flatbuffers::FieldIndexToOffset(0), 0); } 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. void ValueTest() { // 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_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_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() { |