diff --git a/llvm/lib/Support/JSON.cpp b/llvm/lib/Support/JSON.cpp --- a/llvm/lib/Support/JSON.cpp +++ b/llvm/lib/Support/JSON.cpp @@ -509,13 +509,25 @@ S.push_back(next()); char *End; // Try first to parse as integer, and if so preserve full 64 bits. - // strtoll returns long long >= 64 bits, so check it's in range too. - auto I = std::strtoll(S.c_str(), &End, 10); - if (End == S.end() && I >= std::numeric_limits::min() && - I <= std::numeric_limits::max()) { + // We check for errno for out of bounds errors and for End == S.end() + // to make sure that the numeric string is not malformed. + errno = 0; + int64_t I = std::strtoll(S.c_str(), &End, 10); + if (End == S.end() && errno != ERANGE) { Out = int64_t(I); return true; } + // strtroull has a special handling for negative numbers, but in this + // case we don't want to do that because negative numbers were already + // handled in the previous block. + if (First != '-') { + errno = 0; + uint64_t UI = std::strtoull(S.c_str(), &End, 10); + if (End == S.end() && errno != ERANGE) { + Out = UI; + return true; + } + } // If it's not an integer Out = std::strtod(S.c_str(), &End); return End == S.end() || parseError("Invalid JSON value (number?)"); diff --git a/llvm/unittests/Support/JSONTest.cpp b/llvm/unittests/Support/JSONTest.cpp --- a/llvm/unittests/Support/JSONTest.cpp +++ b/llvm/unittests/Support/JSONTest.cpp @@ -362,19 +362,80 @@ uint64_t Var = 3100100100; EXPECT_EQ(Val, Var); + Val = uint64_t{std::numeric_limits::max()}; + Var = std::numeric_limits::max(); + EXPECT_EQ(Val, Var); + // Test the parse() part. - const char *Str = "4611686018427387905"; - llvm::Expected Doc = parse(Str); + { + const char *Str = "4611686018427387905"; + llvm::Expected Doc = parse(Str); - EXPECT_TRUE(!!Doc); - EXPECT_EQ(Doc->getAsInteger(), int64_t{4611686018427387905}); - EXPECT_EQ(Doc->getAsUINT64(), uint64_t{4611686018427387905}); - - const char *Str2 = "-78278238238328222"; - llvm::Expected Doc2 = parse(Str2); - EXPECT_TRUE(!!Doc2); - EXPECT_EQ(Doc2->getAsInteger(), int64_t{-78278238238328222}); - EXPECT_EQ(Doc2->getAsUINT64(), llvm::None); + EXPECT_TRUE(!!Doc); + EXPECT_EQ(Doc->getAsInteger(), int64_t{4611686018427387905}); + EXPECT_EQ(Doc->getAsUINT64(), uint64_t{4611686018427387905}); + } + + { + const char *Str = "-78278238238328222"; + llvm::Expected Doc = parse(Str); + + EXPECT_TRUE(!!Doc); + EXPECT_EQ(Doc->getAsInteger(), int64_t{-78278238238328222}); + EXPECT_EQ(Doc->getAsUINT64(), llvm::None); + } + + // Test with the largest 64 signed int. + { + const char *Str = "9223372036854775807"; + llvm::Expected Doc = parse(Str); + + EXPECT_TRUE(!!Doc); + EXPECT_EQ(Doc->getAsInteger(), int64_t{9223372036854775807}); + EXPECT_EQ(Doc->getAsUINT64(), uint64_t{9223372036854775807}); + } + + // Test with the largest 64 unsigned int. + { + const char *Str = "18446744073709551615"; + llvm::Expected Doc = parse(Str); + + EXPECT_TRUE(!!Doc); + EXPECT_EQ(Doc->getAsInteger(), None); + EXPECT_EQ(Doc->getAsUINT64(), uint64_t{18446744073709551615u}); + } + + // Test with a number that is too big for 64 bits. + { + const char *Str = "184467440737095516150"; + llvm::Expected Doc = parse(Str); + + EXPECT_TRUE(!!Doc); + EXPECT_EQ(Doc->getAsInteger(), None); + EXPECT_EQ(Doc->getAsUINT64(), None); + // The number was parsed as a double. + EXPECT_TRUE(!!Doc->getAsNumber()); + } + + // Test with a negative number that is too small for 64 bits. + { + const char *Str = "-18446744073709551615"; + llvm::Expected Doc = parse(Str); + + EXPECT_TRUE(!!Doc); + EXPECT_EQ(Doc->getAsInteger(), None); + EXPECT_EQ(Doc->getAsUINT64(), None); + // The number was parsed as a double. + EXPECT_TRUE(!!Doc->getAsNumber()); + } + // Test with a large number that is malformed. + { + const char *Str = "184467440737095516150.12.12"; + llvm::Expected Doc = parse(Str); + + EXPECT_EQ("[1:27, byte=27]: Invalid JSON value (number?)", + llvm::toString(Doc.takeError())); + } } // Sample struct with typical JSON-mapping rules.