summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorWouter van Oortmerssen <aardappel@gmail.com>2017-01-30 17:07:55 -0800
committerWouter van Oortmerssen <aardappel@gmail.com>2017-02-01 14:18:28 -0800
commit29574282a283ddc7904d096d27b783b794da7e91 (patch)
tree5baeccd9063df82d9ef31cc6c2bdd8983babd6f2
parent2dd6ba57d132d34172077b637b532e21aa6dda8a (diff)
downloadflatbuffers-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.h2
-rw-r--r--include/flatbuffers/util.h6
-rw-r--r--src/idl_parser.cpp18
-rw-r--r--tests/test.cpp29
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() {