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
Fix wrap around issues on large numerics #543
Changes from 2 commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -96,7 +96,7 @@ static FASTCALL_ATTR JSOBJ FASTCALL_MSVC decode_numeric (struct DecoderState *ds | |
int chr; | ||
char *offset = ds->start; | ||
|
||
JSUINT64 overflowLimit = LLONG_MAX; | ||
JSUINT64 overflowLimit = ULLONG_MAX; | ||
|
||
if (*(offset) == 'I') { | ||
goto DECODE_INF; | ||
|
@@ -131,15 +131,17 @@ static FASTCALL_ATTR JSOBJ FASTCALL_MSVC decode_numeric (struct DecoderState *ds | |
case '8': | ||
case '9': | ||
{ | ||
// detect overflow on digit shift | ||
if ((intValue * 10ULL) % 10 != 0) | ||
{ | ||
hasError = 1; | ||
} | ||
|
||
//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) | ||
{ | ||
hasError = 1; | ||
} | ||
else if (intNeg == -1 && intValue > overflowLimit) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Doesn't the removal of this check mean that there is no test against the smaller |
||
if (prevIntValue > intValue) | ||
{ | ||
hasError = 1; | ||
} | ||
|
@@ -169,7 +171,7 @@ static FASTCALL_ATTR JSOBJ FASTCALL_MSVC decode_numeric (struct DecoderState *ds | |
} | ||
else if (intNeg == -1) | ||
{ | ||
return SetError(ds, -1, overflowLimit == LLONG_MAX ? "Value is too big!" : "Value is too small"); | ||
return SetError(ds, -1, overflowLimit == LLONG_MAX ? "Value is too big!" : "Value is too small!"); | ||
hugovk marked this conversation as resolved.
Show resolved
Hide resolved
|
||
} | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Is the There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. (P.S. If we're ditching |
||
} | ||
goto BREAK_INT_LOOP; | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -1055,3 +1055,17 @@ def test_decode_string_utf8(): | |
heap = hp.heapu() | ||
print(heap) | ||
""" | ||
|
||
|
||
@pytest.mark.parametrize( | ||
"test_input", | ||
[ | ||
("33333333303333333333"), | ||
("18446744073709551616"), # 64 bit | ||
("-18446744073709551616"), # 64 bit | ||
("-80888888888888888888"), | ||
], | ||
) | ||
def test_decode_big_numeric(test_input): | ||
with pytest.raises(ujson.JSONDecodeError): | ||
ujson.loads(test_input) | ||
Comment on lines
+1060
to
+1071
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This should be merged with |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Would
if (intValue > ULLONG_MAX / 10)
not be equivalent? It's less headache inducing and probably fractionally more performant since theULLONG_MAX / 10
will be evaluated at compile time leaving just the>
operation at runtime.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, I think that's functionally identical. In both cases, an
intValue
ofULLONG_MAX / 10 = 1844674407370955161
would pass the check, as it should since it does not overflow on the multiplication. It might still overflow on the addition if the next digit is 6 to 9, but that would be caught in the check below. AndintValue = ULLONG_MAX / 10 + 1
would fail this added check in both forms.