Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Integer parsing: always detect overflows #544

Merged
merged 3 commits into from Jun 1, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
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 @@ -592,7 +592,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