-
-
Notifications
You must be signed in to change notification settings - Fork 7.1k
Fix ndarray dimension signedness, fix ndarray length overflow, close #3519 #3521
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
Conversation
There is still an issue with MSVC 2019. |
More accurately, 32bit builds, which should be a clue. |
if (JSON_HEDLEY_UNLIKELY(!sax->number_integer(static_cast<number_integer_t>(i)))) | ||
if (result == 0) // because dim elements shall not have zeros, result = 0 means overflow happened | ||
{ | ||
return sax->parse_error(chars_read, get_token_string(), parse_error::create(113, chars_read, exception_message(input_format, "excessive ndarray size caused overflow", "size"), nullptr)); |
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.
113 does not feel right here. What about https://json.nlohmann.me/home/exceptions/#jsonexceptionout_of_range408?
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.
I will change it to 408
I think this is what happened: when reading the uint64 number in the dimension vector on a 32 bit windows, the overflow happened earlier, i.e when reading the uint64 json/include/nlohmann/detail/input/binary_reader.hpp Lines 2153 to 2160 in b6d00d1
I am wondering if there is a way for me to tell when an overflow happen when reading a large number on win32? |
Because the size of Somehting like this should suffice: #include <limits>
if(value > std::numeric_limits<std::size_t>::max()) throw ...; |
now I am wondering why this was not tested in other binary formats, for example UBJSON? upon reading this part of the test, is it true that the test simply compares the overflowed value and allow overflow to happen on 32 bit system? https://github.com/nlohmann/json/blob/develop/tests/src/unit-ubjson.cpp#L510-L558 |
The test uses Whenever a 64bit value is read and used as the size for a container, that's where things can go wrong. I'm curious if the UBJSON code accounts for this or why it doesn't need to. |
I added the below
|
Depending on your compiler, you may be able to build 32bit executables by configuring the CMake project with (Edit: On my system that does result in Otherwise, just commit and run it through CI. |
@falbrechtskirchinger, thanks, after installing cross-compilation packages, I was able to test it on -m32. Just commited the change, but realized that coverage will be a problem ... |
I figured that would be a problem but couldn't think of the proper warning flag when I tested. Let me see if I can come up with a better solution ... |
I have a proof of concept. This might be overengineered. @fangq I'll sleep on it and submit a PR against your branch tomorrow (for reference, it's past 9 pm here) if I can't come up with a less involved solution. template<typename T, typename U, bool = (std::numeric_limits<U>::max() < std::numeric_limits<T>::max()), typename = std::enable_if_t<std::is_unsigned_v<T> && std::is_unsigned_v<U>>>
struct value_in_range_of_impl;
template<typename T, typename U>
struct value_in_range_of_impl<T, U, false>
{
static constexpr bool test(U val) { return val < std::numeric_limits<T>::max(); }
};
template<typename T, typename U>
struct value_in_range_of_impl<T, U, true>
{
static constexpr bool test(U /*val*/) { return true; }
};
template<typename T>
constexpr bool value_in_range_of_size_t(T val)
{
return value_in_range_of_impl<std::size_t, T>::test(val);
} |
I tried to open a PR and
There's still a problem with the UBJSON unit test. I assume that's because the range check changes the exception type. |
@nlohmann How would like to address coverage? if (number > std::numeric_limits<std::size_t>::max())
{
return sax->parse_error(chars_read, get_token_string(), parse_error::create(408, chars_read,
exception_message(input_format, "integer value overflow", "size"), nullptr));
} (Edit: This code was copied from the old coverage report.) If that's acceptable, I might as well open another PR instead of having @fangq go through the trouble of cherry-picking from my branch. |
@falbrechtskirchinger I would rather have a test suite compiled with 32 bits that test exactly this issue. |
How would that work with coverage/coveralls? I'm not super familiar with lcov/gcov. Is it possible to collect coverage information from multiple builds? |
We collect coverage reports for anything executed by CTest. If we have another test binary that contains tests relevant for 32 bits and add it to the test suite, the results should appear in the coverage report automatically. |
Ok, a separate test shouldn't be too difficult. I just need to figure out, when |
hi @nlohmann, sorry for the new bug from my code.
I debugged this, and found there were two issues:
with this patch, I was able to fix both, an additional test was added to verify both, the fuzzer data now raise an "excessive ndarray size caused overflow" error.
One thing I want to verify with you is the error code, now I am using 113, let me know if there is a better code. if the length is non-zero and passed to sax functions, it raise a 408 error "excessive array size". but I am capturing this overflow before that.