mirror of
https://github.com/nlohmann/json.git
synced 2026-02-25 12:56:26 +00:00
Fix ndarray dimension signedness, fix ndarray length overflow (2); add 32bit unit test (#3523)
* Fix ndarray dimension signness, fix ndarray length overflow, close #3519 * detect size overflow in ubjson and bjdata * force reformatting * Fix MSVC compiler warning * Add value_in_range_of trait * Use value_in_range_of trait * Correct 408 parse_errors to out_of_range * Add 32bit unit test The test can be enabled by setting JSON_32bitTest=ON. * Exclude unreachable lines from coverage Certain lines are unreachable in 64bit builds. Co-authored-by: Qianqian Fang <fangqq@gmail.com>
This commit is contained in:
committed by
GitHub
parent
b6d00d1897
commit
48a102c2c5
@@ -29,6 +29,8 @@ SOFTWARE.
|
||||
|
||||
#include "doctest_compatibility.h"
|
||||
|
||||
#include <climits>
|
||||
#include <limits>
|
||||
#include <nlohmann/json.hpp>
|
||||
using nlohmann::json;
|
||||
|
||||
@@ -116,6 +118,112 @@ class SaxCountdown
|
||||
};
|
||||
} // namespace
|
||||
|
||||
// at some point in the future, a unit test dedicated to type traits might be a good idea
|
||||
template <typename OfType, typename T, bool MinInRange, bool MaxInRange>
|
||||
struct trait_test_arg
|
||||
{
|
||||
using of_type = OfType;
|
||||
using type = T;
|
||||
static constexpr bool min_in_range = MinInRange;
|
||||
static constexpr bool max_in_range = MaxInRange;
|
||||
};
|
||||
|
||||
TEST_CASE_TEMPLATE_DEFINE("value_in_range_of trait", T, value_in_range_of_test)
|
||||
{
|
||||
using nlohmann::detail::value_in_range_of;
|
||||
|
||||
using of_type = typename T::of_type;
|
||||
using type = typename T::type;
|
||||
constexpr bool min_in_range = T::min_in_range;
|
||||
constexpr bool max_in_range = T::max_in_range;
|
||||
|
||||
type val_min = std::numeric_limits<type>::min();
|
||||
type val_min2 = val_min + 1;
|
||||
type val_max = std::numeric_limits<type>::max();
|
||||
type val_max2 = val_max - 1;
|
||||
|
||||
REQUIRE(CHAR_BIT == 8);
|
||||
|
||||
std::string of_type_str;
|
||||
if (std::is_unsigned<of_type>::value)
|
||||
{
|
||||
of_type_str += "u";
|
||||
}
|
||||
of_type_str += "int";
|
||||
of_type_str += std::to_string(sizeof(of_type) * 8);
|
||||
|
||||
INFO("of_type := ", of_type_str);
|
||||
|
||||
std::string type_str;
|
||||
if (std::is_unsigned<type>::value)
|
||||
{
|
||||
type_str += "u";
|
||||
}
|
||||
type_str += "int";
|
||||
type_str += std::to_string(sizeof(type) * 8);
|
||||
|
||||
INFO("type := ", type_str);
|
||||
|
||||
CAPTURE(val_min);
|
||||
CAPTURE(min_in_range);
|
||||
CAPTURE(val_max);
|
||||
CAPTURE(max_in_range);
|
||||
|
||||
if (min_in_range)
|
||||
{
|
||||
CHECK(value_in_range_of<of_type>(val_min));
|
||||
CHECK(value_in_range_of<of_type>(val_min2));
|
||||
}
|
||||
else
|
||||
{
|
||||
CHECK_FALSE(value_in_range_of<of_type>(val_min));
|
||||
CHECK_FALSE(value_in_range_of<of_type>(val_min2));
|
||||
}
|
||||
|
||||
if (max_in_range)
|
||||
{
|
||||
CHECK(value_in_range_of<of_type>(val_max));
|
||||
CHECK(value_in_range_of<of_type>(val_max2));
|
||||
}
|
||||
else
|
||||
{
|
||||
CHECK_FALSE(value_in_range_of<of_type>(val_max));
|
||||
CHECK_FALSE(value_in_range_of<of_type>(val_max2));
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE_TEMPLATE_INVOKE(value_in_range_of_test, \
|
||||
trait_test_arg<std::int32_t, std::int32_t, true, true>, \
|
||||
trait_test_arg<std::int32_t, std::uint32_t, true, false>, \
|
||||
trait_test_arg<std::uint32_t, std::int32_t, false, true>, \
|
||||
trait_test_arg<std::uint32_t, std::uint32_t, true, true>, \
|
||||
trait_test_arg<std::int32_t, std::int64_t, false, false>, \
|
||||
trait_test_arg<std::int32_t, std::uint64_t, true, false>, \
|
||||
trait_test_arg<std::uint32_t, std::int64_t, false, false>, \
|
||||
trait_test_arg<std::uint32_t, std::uint64_t, true, false>, \
|
||||
trait_test_arg<std::int64_t, std::int32_t, true, true>, \
|
||||
trait_test_arg<std::int64_t, std::uint32_t, true, true>, \
|
||||
trait_test_arg<std::uint64_t, std::int32_t, false, true>, \
|
||||
trait_test_arg<std::uint64_t, std::uint32_t, true, true>, \
|
||||
trait_test_arg<std::int64_t, std::int64_t, true, true>, \
|
||||
trait_test_arg<std::int64_t, std::uint64_t, true, false>, \
|
||||
trait_test_arg<std::uint64_t, std::int64_t, false, true>, \
|
||||
trait_test_arg<std::uint64_t, std::uint64_t, true, true>);
|
||||
|
||||
#if SIZE_MAX == 0xffffffff
|
||||
TEST_CASE_TEMPLATE_INVOKE(value_in_range_of_test, \
|
||||
trait_test_arg<std::size_t, std::int32_t, false, true>, \
|
||||
trait_test_arg<std::size_t, std::uint32_t, true, true>, \
|
||||
trait_test_arg<std::size_t, std::int64_t, false, false>, \
|
||||
trait_test_arg<std::size_t, std::uint64_t, true, false>);
|
||||
#else
|
||||
TEST_CASE_TEMPLATE_INVOKE(value_in_range_of_test, \
|
||||
trait_test_arg<std::size_t, std::int32_t, false, true>, \
|
||||
trait_test_arg<std::size_t, std::uint32_t, true, true>, \
|
||||
trait_test_arg<std::size_t, std::int64_t, false, true>, \
|
||||
trait_test_arg<std::size_t, std::uint64_t, true, true>);
|
||||
#endif
|
||||
|
||||
TEST_CASE("BJData")
|
||||
{
|
||||
SECTION("individual values")
|
||||
@@ -2511,6 +2619,7 @@ TEST_CASE("BJData")
|
||||
std::vector<uint8_t> vI = {'[', '#', 'I', 0x00, 0xF1};
|
||||
std::vector<uint8_t> vl = {'[', '#', 'l', 0x00, 0x00, 0x00, 0xF2};
|
||||
std::vector<uint8_t> vL = {'[', '#', 'L', 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF3};
|
||||
std::vector<uint8_t> vM = {'[', '$', 'M', '#', '[', 'I', 0x00, 0x20, 'M', 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0xFF, ']'};
|
||||
|
||||
json _;
|
||||
CHECK_THROWS_WITH_AS(_ = json::from_bjdata(v1), "[json.exception.parse_error.113] parse error at byte 4: syntax error while parsing BJData size: count in an optimized container must be positive", json::parse_error&);
|
||||
@@ -2535,10 +2644,17 @@ TEST_CASE("BJData")
|
||||
CHECK(json::from_bjdata(vI, true, false).is_discarded());
|
||||
|
||||
CHECK_THROWS_WITH_AS(_ = json::from_bjdata(vl), "[json.exception.parse_error.113] parse error at byte 7: syntax error while parsing BJData size: count in an optimized container must be positive", json::parse_error&);
|
||||
CHECK(json::from_bjdata(vI, true, false).is_discarded());
|
||||
CHECK(json::from_bjdata(vl, true, false).is_discarded());
|
||||
|
||||
CHECK_THROWS_WITH_AS(_ = json::from_bjdata(vL), "[json.exception.parse_error.113] parse error at byte 11: syntax error while parsing BJData size: count in an optimized container must be positive", json::parse_error&);
|
||||
CHECK(json::from_bjdata(vI, true, false).is_discarded());
|
||||
CHECK(json::from_bjdata(vL, true, false).is_discarded());
|
||||
|
||||
#if SIZE_MAX == 0xffffffff
|
||||
CHECK_THROWS_WITH_AS(_ = json::from_bjdata(vM), "[json.exception.out_of_range.408] syntax error while parsing BJData size: integer value overflow", json::out_of_range&);
|
||||
#else
|
||||
CHECK_THROWS_WITH_AS(_ = json::from_bjdata(vM), "[json.exception.out_of_range.408] syntax error while parsing BJData size: excessive ndarray size caused overflow", json::out_of_range&);
|
||||
#endif
|
||||
CHECK(json::from_bjdata(vM, true, false).is_discarded());
|
||||
}
|
||||
|
||||
SECTION("do not accept NTFZ markers in ndarray optimized type (with count)")
|
||||
|
||||
Reference in New Issue
Block a user