Commit 3400727f authored by Ben Gertzfield's avatar Ben Gertzfield

Fix undefined behavior in CheckBitsFit bit-shift on size_t

parent 77742a3f
...@@ -69,13 +69,16 @@ inline CheckedError NoError() { return CheckedError(false); } ...@@ -69,13 +69,16 @@ inline CheckedError NoError() { return CheckedError(false); }
// Ensure that integer values we parse fit inside the declared integer type. // Ensure that integer values we parse fit inside the declared integer type.
CheckedError Parser::CheckBitsFit(int64_t val, size_t bits) { CheckedError Parser::CheckBitsFit(int64_t val, size_t bits) {
// Bits we allow to be used. // Left-shifting a 64-bit value by 64 bits or more is undefined
auto mask = static_cast<int64_t>((1ull << bits) - 1); // behavior (C99 6.5.7), so check *before* we shift.
if (bits < 64 && if (bits < 64) {
(val & ~mask) != 0 && // Positive or unsigned. // Bits we allow to be used.
(val | mask) != -1) // Negative. auto mask = static_cast<int64_t>((1ull << bits) - 1);
return Error("constant does not fit in a " + NumToString(bits) + if ((val & ~mask) != 0 && // Positive or unsigned.
"-bit field"); (val | mask) != -1) // Negative.
return Error("constant does not fit in a " + NumToString(bits) +
"-bit field");
}
return NoError(); return NoError();
} }
......
...@@ -819,6 +819,33 @@ void EnumStringsTest() { ...@@ -819,6 +819,33 @@ void EnumStringsTest() {
"{ F:[ \"E.C\", \"E.A E.B E.C\" ] }"), true); "{ F:[ \"E.C\", \"E.A E.B E.C\" ] }"), true);
} }
void IntegerOutOfRangeTest() {
TestError("table T { F:byte; } root_type T; { F:256 }",
"constant does not fit");
TestError("table T { F:byte; } root_type T; { F:-257 }",
"constant does not fit");
TestError("table T { F:ubyte; } root_type T; { F:256 }",
"constant does not fit");
TestError("table T { F:ubyte; } root_type T; { F:-257 }",
"constant does not fit");
TestError("table T { F:short; } root_type T; { F:65536 }",
"constant does not fit");
TestError("table T { F:short; } root_type T; { F:-65537 }",
"constant does not fit");
TestError("table T { F:ushort; } root_type T; { F:65536 }",
"constant does not fit");
TestError("table T { F:ushort; } root_type T; { F:-65537 }",
"constant does not fit");
TestError("table T { F:int; } root_type T; { F:4294967296 }",
"constant does not fit");
TestError("table T { F:int; } root_type T; { F:-4294967297 }",
"constant does not fit");
TestError("table T { F:uint; } root_type T; { F:4294967296 }",
"constant does not fit");
TestError("table T { F:uint; } root_type T; { F:-4294967297 }",
"constant does not fit");
}
void UnicodeTest() { void UnicodeTest() {
flatbuffers::Parser parser; flatbuffers::Parser parser;
TEST_EQ(parser.Parse("table T { F:string; }" TEST_EQ(parser.Parse("table T { F:string; }"
...@@ -878,6 +905,7 @@ int main(int /*argc*/, const char * /*argv*/[]) { ...@@ -878,6 +905,7 @@ int main(int /*argc*/, const char * /*argv*/[]) {
ErrorTest(); ErrorTest();
ScientificTest(); ScientificTest();
EnumStringsTest(); EnumStringsTest();
IntegerOutOfRangeTest();
UnicodeTest(); UnicodeTest();
UnknownFieldsTest(); UnknownFieldsTest();
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment