Reading large numbers from the JSON causes a bad_cast exception even when the target datatype can store the number
Closed this issue · 1 comments
MageFromAntares commented
Hi,
When storing large numbers in a JSON (for example INT64_MAX) a bad_cast error gets thrown instead of returning the value even when the target data type can store the value.
#include <iostream>
#include <sstream>
#include <string>
#include <cppcms/json.h>
std::string const small_number_json = {
R"({
"test": 51245,
})"
};
const std::string small_number_as_string = "51245";
std::string const too_large_number_json = {
R"({
"test": 9223372036854775807,
})"
};
const std::string too_large_number_as_string = "9223372036854775807";
void test_json_and_string(const std::string& json, const std::string& number)
{
cppcms::json::value my_root;
long long my_number_as_longlong;
std::istringstream my_root_stream{json};
std::istringstream my_number_stream{number};
my_root_stream >> my_root;
my_number_stream >> my_number_as_longlong;
std::cout << my_number_as_longlong << std::endl;
std::cout << my_root.get<long long>("test") << std::endl;
}
int main(void)
{
test_json_and_string(small_number_json, small_number_as_string); // OK
test_json_and_string(too_large_number_json, too_large_number_as_string); // FAIL
return 0;
}
The same happens when using int64_t.
Thanks.
artyom-beilis commented
This isn't a bug this is actually right behavior.
JSON and JavaScript in general requires numbers to be represented as at least double and this is what cppcms::json does - it keeps values as double.
INT64_MAX
can't be represented exactly in double values that has mantissa of 53 bits and thus can't represnet 64 bit integer correctly.
Now take a look on the sample:
#include <iterator>
#include <iostream>
int main()
{
double v=9223372036854775807.0;
std::cout << std::fixed;
std::cout << "Double " << v << std::endl;
std::cout << "Int64 MAX " << INT64_MAX << std::endl;
long long iv = static_cast<long long>(v);
std::cout << "Casted " << iv << std::endl;
std::cout << "Int=doub " << (v==iv) << std::endl;
}
Casting to long long will lead to negative number which is clearly wrong. this the behavior is correct