mirror of
https://github.com/XRPLF/rippled.git
synced 2025-12-06 17:27:55 +00:00
Properly handle edge-cases when parsing JSON integers (RIPD-470):
* Properly handle both unsigned and signed integers * Return parsing error for overlong JSON numbers * Implement unit test checking the edge cases that are of interest
This commit is contained in:
@@ -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::Int>( 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::Int>( value );
|
||||
else
|
||||
currentValue () = static_cast<Value::UInt>( value );
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user