diff --git a/src/json.hpp b/src/json.hpp index 67c6b6fc..0dfc11fd 100644 --- a/src/json.hpp +++ b/src/json.hpp @@ -10643,7 +10643,22 @@ basic_json_parser_66: } else if (type == value_t::number_integer) { - result.m_value.number_integer = -static_cast(value); + // invariant: if we parsed a '-', the absolute value is between + // 0 (we allow -0) and max == -INT64_MIN + assert(value >= 0); + assert(value <= max); + + if (value == max) + { + // we cannot simply negate value (== max == -INT64_MIN), + // see https://github.com/nlohmann/json/issues/389 + result.m_value.number_integer = INT64_MIN; + } + else + { + // all other values can be negated safely + result.m_value.number_integer = -static_cast(value); + } } else { diff --git a/src/json.hpp.re2c b/src/json.hpp.re2c index 2ad5e7ce..72fd0474 100644 --- a/src/json.hpp.re2c +++ b/src/json.hpp.re2c @@ -9793,7 +9793,22 @@ class basic_json } else if (type == value_t::number_integer) { - result.m_value.number_integer = -static_cast(value); + // invariant: if we parsed a '-', the absolute value is between + // 0 (we allow -0) and max == -INT64_MIN + assert(value >= 0); + assert(value <= max); + + if (value == max) + { + // we cannot simply negate value (== max == -INT64_MIN), + // see https://github.com/nlohmann/json/issues/389 + result.m_value.number_integer = INT64_MIN; + } + else + { + // all other values can be negated safely + result.m_value.number_integer = -static_cast(value); + } } else { diff --git a/test/src/unit-regression.cpp b/test/src/unit-regression.cpp index e04513ca..f6d05eff 100644 --- a/test/src/unit-regression.cpp +++ b/test/src/unit-regression.cpp @@ -516,4 +516,21 @@ TEST_CASE("regression tests") CHECK_THROWS_AS(j << ss, std::invalid_argument); CHECK_THROWS_WITH(j << ss, "parse error - unexpected end of input"); } + + SECTION("issue #389 - Integer-overflow (OSS-Fuzz issue 267)") + { + // original test case + json j1 = json::parse("-9223372036854775808"); + CHECK(j1.is_number_integer()); + CHECK(j1.get() == INT64_MIN); + + // edge case (+1; still an integer) + json j2 = json::parse("-9223372036854775807"); + CHECK(j2.is_number_integer()); + CHECK(j2.get() == INT64_MIN + 1); + + // edge case (-1; overflow -> floats) + json j3 = json::parse("-9223372036854775809"); + CHECK(j3.is_number_float()); + } }