Narrows template ascii routines to prevent a possible signed overflow in generic...
authorVladimir Glavnyy <31897320+vglavnyy@users.noreply.github.com>
Mon, 11 Mar 2019 17:26:28 +0000 (00:26 +0700)
committerWouter van Oortmerssen <aardappel@gmail.com>
Mon, 11 Mar 2019 17:26:28 +0000 (10:26 -0700)
include/flatbuffers/util.h
src/idl_parser.cpp

index 275747b..4367bbe 100644 (file)
@@ -35,19 +35,19 @@ namespace flatbuffers {
 
 // @locale-independent functions for ASCII characters set.
 
-// Check that integer scalar is in closed range: (a <= x <= b)
+// Fast checking that character lies in closed range: [a <= x <= b]
 // using one compare (conditional branch) operator.
-template<typename T> inline bool check_in_range(T x, T a, T b) {
+inline bool check_ascii_range(char x, char a, char b) {
+  FLATBUFFERS_ASSERT(a <= b);
   // (Hacker's Delight): `a <= x <= b` <=> `(x-a) <={u} (b-a)`.
-  FLATBUFFERS_ASSERT(a <= b);  // static_assert only if 'a' & 'b' templated
-  typedef typename flatbuffers::make_unsigned<T>::type U;
-  return (static_cast<U>(x - a) <= static_cast<U>(b - a));
+  // The x, a, b will be promoted to int and subtracted without overflow.
+  return static_cast<unsigned int>(x - a) <= static_cast<unsigned int>(b - a);
 }
 
 // Case-insensitive isalpha
 inline bool is_alpha(char c) {
   // ASCII only: alpha to upper case => reset bit 0x20 (~0x20 = 0xDF).
-  return check_in_range(c & 0xDF, 'a' & 0xDF, 'z' & 0xDF);
+  return check_ascii_range(c & 0xDF, 'a' & 0xDF, 'z' & 0xDF);
 }
 
 // Check (case-insensitive) that `c` is equal to alpha.
@@ -62,11 +62,11 @@ inline bool is_alpha_char(char c, char alpha) {
 // functions that are not affected by the currently installed C locale. although
 // some implementations (e.g. Microsoft in 1252 codepage) may classify
 // additional single-byte characters as digits.
-inline bool is_digit(char c) { return check_in_range(c, '0', '9'); }
+inline bool is_digit(char c) { return check_ascii_range(c, '0', '9'); }
 
 inline bool is_xdigit(char c) {
   // Replace by look-up table.
-  return is_digit(c) || check_in_range(c & 0xDF, 'a' & 0xDF, 'f' & 0xDF);
+  return is_digit(c) || check_ascii_range(c & 0xDF, 'a' & 0xDF, 'f' & 0xDF);
 }
 
 // Case-insensitive isalnum
index bfeb426..583538f 100644 (file)
@@ -374,7 +374,7 @@ CheckedError Parser::Next() {
                   "illegal Unicode sequence (unpaired high surrogate)");
             }
             // reset if non-printable
-            attr_is_trivial_ascii_string_ &= check_in_range(*cursor_, ' ', '~');
+            attr_is_trivial_ascii_string_ &= check_ascii_range(*cursor_, ' ', '~');
 
             attribute_ += *cursor_++;
           }
@@ -476,7 +476,7 @@ CheckedError Parser::Next() {
         }
         std::string ch;
         ch = c;
-        if (false == check_in_range(c, ' ', '~')) ch = "code: " + NumToString(c);
+        if (false == check_ascii_range(c, ' ', '~')) ch = "code: " + NumToString(c);
         return Error("illegal character: " + ch);
     }
   }