Skip to content

Commit

Permalink
Merge pull request #544 from NaN-git/main
Browse files Browse the repository at this point in the history
Integer parsing: always detect overflows
  • Loading branch information
hugovk committed Jun 1, 2022
2 parents 66bb6e0 + 0a0e111 commit f71d7c2
Show file tree
Hide file tree
Showing 2 changed files with 32 additions and 26 deletions.
55 changes: 29 additions & 26 deletions lib/ultrajsondec.c
Expand Up @@ -92,23 +92,31 @@ static FASTCALL_ATTR JSOBJ FASTCALL_MSVC decode_numeric (struct DecoderState *ds
int intNeg = 1;
int hasError = 0;
JSUINT64 intValue;
JSUINT64 prevIntValue;
JSUINT64 addIntValue;
int chr;
char *offset = ds->start;

JSUINT64 overflowLimit = LLONG_MAX;
JSUINT64 maxIntValue = ULLONG_MAX;
JSUINT64 overflowLimit = maxIntValue / 10LLU;

if (*(offset) == 'I') {
if (*(offset) == 'I')
{
goto DECODE_INF;
}
else if (*(offset) == 'N')
{
goto DECODE_NAN;
}
else if (*(offset) == '-')
{
offset++;
intNeg = -1;
if (*(offset) == 'I')
{
goto DECODE_INF;
} else if (*(offset) == 'N') {
goto DECODE_NAN;
} else if (*(offset) == '-') {
offset++;
intNeg = -1;
if (*(offset) == 'I') {
goto DECODE_INF;
}
overflowLimit = LLONG_MIN;
}
maxIntValue = -(JSUINT64) LLONG_MIN;
overflowLimit = maxIntValue / 10LL;
}

// Scan integer part
Expand All @@ -131,19 +139,21 @@ static FASTCALL_ATTR JSOBJ FASTCALL_MSVC decode_numeric (struct DecoderState *ds
case '8':
case '9':
{
//PERF: Don't do 64-bit arithmetic here unless we know we have to
prevIntValue = intValue;
intValue = intValue * 10ULL + (JSLONG) (chr - 48);

if (intNeg == 1 && prevIntValue > intValue)
// check whether multiplication would be out of bounds
if (intValue > overflowLimit)
{
hasError = 1;
}
else if (intNeg == -1 && intValue > overflowLimit)
intValue *= 10ULL;
addIntValue = (JSUINT64) (chr - 48);

// check whether addition would be out of bounds
if (maxIntValue - intValue < addIntValue)
{
hasError = 1;
}

intValue += addIntValue;
offset ++;
break;
}
Expand All @@ -163,14 +173,7 @@ static FASTCALL_ATTR JSOBJ FASTCALL_MSVC decode_numeric (struct DecoderState *ds
{
if (hasError)
{
if (intNeg == 1)
{
return SetError(ds, -1, "Value is too big!");
}
else if (intNeg == -1)
{
return SetError(ds, -1, overflowLimit == LLONG_MAX ? "Value is too big!" : "Value is too small");
}
return SetError(ds, -1, intNeg == 1 ? "Value is too big" : "Value is too small");
}
goto BREAK_INT_LOOP;
break;
Expand Down
3 changes: 3 additions & 0 deletions tests/test_ujson.py
Expand Up @@ -600,7 +600,10 @@ def test_decode_range_raises(test_input, expected):
("[]]", ujson.JSONDecodeError), # array unmatched bracket fail
("18446744073709551616", ujson.JSONDecodeError), # too big value
("-90223372036854775809", ujson.JSONDecodeError), # too small value
("-23058430092136939529", ujson.JSONDecodeError), # too small value
("-11529215046068469760", ujson.JSONDecodeError), # too small value
("18446744073709551616", ujson.JSONDecodeError), # very too big value
("23058430092136939529", ujson.JSONDecodeError), # too big value
("-90223372036854775809", ujson.JSONDecodeError), # very too small value
("{}\n\t a", ujson.JSONDecodeError), # with trailing non whitespaces
("[18446744073709551616]", ujson.JSONDecodeError), # array with big int
Expand Down

0 comments on commit f71d7c2

Please sign in to comment.