Skip to content

Commit

Permalink
Check we don't overflow when casting down integers during parsing
Browse files Browse the repository at this point in the history
  • Loading branch information
ArnaudBienner committed Apr 19, 2024
1 parent 8c391e0 commit da5800c
Show file tree
Hide file tree
Showing 2 changed files with 30 additions and 6 deletions.
30 changes: 24 additions & 6 deletions include/nlohmann/detail/conversions/from_json.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,24 @@ inline void from_json(const BasicJsonType& j, typename std::nullptr_t& n)
n = nullptr;
}

template <typename BasicJsonType, typename ArithmeticTypeTarget, typename ArithmeticTypeSource>
ArithmeticTypeTarget static_cast_check_range(const BasicJsonType& j)
{
const auto val = *j.template get_ptr<ArithmeticTypeSource*>();
const auto min = std::numeric_limits<ArithmeticTypeTarget>::min();
const auto max = std::numeric_limits<ArithmeticTypeTarget>::max();
if (val < min && val > max)
{
JSON_THROW(
out_of_range::create(
406,
"value " + std::to_string(val) + " is out of target integer range [" + std::to_string(min) + ", " +
std::to_string(max) + "]", &j));
}
return static_cast<ArithmeticTypeTarget>(val);
}


// overloads for basic_json template parameters
template < typename BasicJsonType, typename ArithmeticType,
enable_if_t < std::is_arithmetic<ArithmeticType>::value&&
Expand All @@ -54,17 +72,17 @@ void get_arithmetic_value(const BasicJsonType& j, ArithmeticType& val)
{
case value_t::number_unsigned:
{
val = static_cast<ArithmeticType>(*j.template get_ptr<const typename BasicJsonType::number_unsigned_t*>());
val = static_cast_check_range<BasicJsonType, ArithmeticType, const typename BasicJsonType::number_unsigned_t>(j);
break;
}
case value_t::number_integer:
{
val = static_cast<ArithmeticType>(*j.template get_ptr<const typename BasicJsonType::number_integer_t*>());
val = static_cast_check_range<BasicJsonType, ArithmeticType, const typename BasicJsonType::number_integer_t>(j);
break;
}
case value_t::number_float:
{
val = static_cast<ArithmeticType>(*j.template get_ptr<const typename BasicJsonType::number_float_t*>());
val = static_cast_check_range<BasicJsonType, ArithmeticType, const typename BasicJsonType::number_float_t>(j);
break;
}

Expand Down Expand Up @@ -343,17 +361,17 @@ inline void from_json(const BasicJsonType& j, ArithmeticType& val)
{
case value_t::number_unsigned:
{
val = static_cast<ArithmeticType>(*j.template get_ptr<const typename BasicJsonType::number_unsigned_t*>());
val = static_cast_check_range<BasicJsonType, ArithmeticType, const typename BasicJsonType::number_unsigned_t>(j);
break;
}
case value_t::number_integer:
{
val = static_cast<ArithmeticType>(*j.template get_ptr<const typename BasicJsonType::number_integer_t*>());
val = static_cast_check_range<BasicJsonType, ArithmeticType, const typename BasicJsonType::number_integer_t>(j);
break;
}
case value_t::number_float:
{
val = static_cast<ArithmeticType>(*j.template get_ptr<const typename BasicJsonType::number_float_t*>());
val = static_cast_check_range<BasicJsonType, ArithmeticType, const typename BasicJsonType::number_float_t>(j);
break;
}
case value_t::boolean:
Expand Down
6 changes: 6 additions & 0 deletions tests/src/unit-class_parser.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -585,6 +585,12 @@ TEST_CASE("parser class")
CHECK_THROWS_WITH_AS(parser_helper("1.18973e+4932").empty(), "[json.exception.out_of_range.406] number overflow parsing '1.18973e+4932'", json::out_of_range&);
}

SECTION("out-of-range-conversion")
{
// overflows during parsing with casting yield an exception
CHECK_THROWS_WITH_AS(parser_helper("123456").get<int16_t>(), "[json.exception.out_of_range.406] value 123456 is out of target integer range [-32768, 32767]", json::out_of_range&);
}

SECTION("invalid numbers")
{
// numbers must not begin with "+"
Expand Down

0 comments on commit da5800c

Please sign in to comment.