diff --git a/src/ripple/json/impl/Tests.cpp b/src/ripple/json/impl/Tests.cpp index 69ab957cfe..feee14b25b 100644 --- a/src/ripple/json/impl/Tests.cpp +++ b/src/ripple/json/impl/Tests.cpp @@ -38,6 +38,40 @@ public: pass (); } + void testMaxInts () + { + char const* s1 ( + "{\"max_uint\":4294967295" + ",\"min_int\":-2147483648" + ",\"max_int\":2147483647" + ",\"an_int\":2147483646" + ",\"a_uint\":2147483648}" + ); + Json::Value j1; + Json::Reader r1; + + expect (r1.parse (s1, j1), "parsing integer edge cases"); + expect (j1["max_uint"].asUInt() == 4294967295, "max_uint"); + expect (j1["min_int"].asInt() == -2147483648, "min_int"); + expect (j1["max_int"].asInt() == 2147483647, "max_int"); + expect (j1["an_int"].asInt() == 2147483646, "an_int"); + expect (j1["a_uint"].asUInt() == 2147483648, "a_uint"); + + char const* s2 ("{\"overflow_uint\":4294967296}"); + Json::Value j2; + Json::Reader r2; + + expect (!r2.parse (s2, j2), "parsing unsigned integer that overflows"); + + char const* s3 ("{\"underflow_int\":-2147483649}"); + Json::Value j3; + Json::Reader r3; + + expect (!r3.parse (s3, j3), "parsing signed integer that underflows"); + + pass (); + } + void test_copy () { @@ -86,6 +120,7 @@ public: void run () { + testMaxInts (); testBadJson (); test_copy (); test_move (); diff --git a/src/ripple/json/impl/json_reader.cpp b/src/ripple/json/impl/json_reader.cpp index 7a2886fe27..955c3f3eda 100644 --- a/src/ripple/json/impl/json_reader.cpp +++ b/src/ripple/json/impl/json_reader.cpp @@ -682,29 +682,57 @@ Reader::decodeNumber ( Token& token ) if ( isNegative ) ++current; - Value::UInt threshold = (isNegative ? Value::UInt (-Value::minInt) - : Value::maxUInt) / 10; - Value::UInt value = 0; + std::int64_t value = 0; - while ( current < token.end_ ) + static_assert(sizeof(value) > sizeof(Value::maxUInt), + "The JSON integer overflow logic will need to be reworked."); + + while (current < token.end_ && (value <= Value::maxUInt)) { Char c = *current++; if ( c < '0' || c > '9' ) - return addError ( "'" + std::string ( token.start_, token.end_ ) + "' is not a number.", token ); + { + return addError ( "'" + std::string ( token.start_, token.end_ ) + + "' is not a number.", token ); + } - if ( value >= threshold ) - return decodeDouble ( token ); + value = (value * 10) + (c - '0'); + } - value = value * 10 + Value::UInt (c - '0'); + // More tokens left -> input is larger than largest possible return value + if (current != token.end_) + { + return addError ( "'" + std::string ( token.start_, token.end_ ) + + "' exceeds the allowable range.", token ); } if ( isNegative ) - currentValue () = -Value::Int ( value ); - else if ( value <= Value::UInt (Value::maxInt) ) - currentValue () = Value::Int ( value ); + { + value = -value; + + if (value < Value::minInt || value > Value::maxInt) + { + return addError ( "'" + std::string ( token.start_, token.end_ ) + + "' exceeds the allowable range.", token ); + } + + currentValue () = static_cast( value ); + } else - currentValue () = value; + { + if (value > Value::maxUInt) + { + return addError ( "'" + std::string ( token.start_, token.end_ ) + + "' exceeds the allowable range.", token ); + } + + // If it's representable as a signed integer, construct it as one. + if ( value <= Value::maxInt ) + currentValue () = static_cast( value ); + else + currentValue () = static_cast( value ); + } return true; }