-
Notifications
You must be signed in to change notification settings - Fork 89
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
JSON parsing fix from steem PR 2178 #15
Conversation
And please add this one: EOSIO/eos@9aa838e |
In order to apply the EOS json patch, need to remove |
Picked EOSIO/eos@842e12f Wrt EOSIO/eos@9aa838e : This patch cannot be applied, because variant_from_stream is called with different stream types which have inconsistent EOF handling. For example, fc::istream doesn't have an eof(), instead, most implementations/subclasses of fc::istream throw an eof_exception on EOF. fc::stringstream has an eof() method and throws. All streams derived from boost::asio throw and don't have an eof(). fc::ifstream has eof() and a read() method that throws and a read_some() method that does This is a horrible mess. Investigating. |
Give me some more time please. Unless you think it's a critical issue. |
Fixed json::from_file, added unit tests. Please review. It seems the graphene codebase only uses one of the configurable parsers, so there is some superfluous stuff in there. |
Fix is incomplete (json::variants_from_string uses relaxed parser) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Mostly fine. Need to fix another issue as discussed in Telegram.
default: | ||
FC_ASSERT( false, "Unknown JSON parser type {ptype}", ("ptype", ptype) ); | ||
} | ||
fc::istream_ptr in( new fc::ifstream( p ) ); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Need std::ios::binary
here.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
By the way, need std::ios::binary
in from_file(...)
below as well.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ifstream always calls open with std::io::binary, see
bitshares-fc/src/io/fstream.cpp
Line 64 in c16bb20
my->ifs.open( bfp, std::ios::binary ); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Got it. Thanks. (Just noticed the 2 comments above are talking about same code).
By the way, in |
FC_THROW_EXCEPTION( parse_error_exception, "Unexpected char '${c}' in \"${s}\"", | ||
("c", c)("s", stringFromToken(in)) ); | ||
} | ||
case '"': |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
How about single quotes? According to stringFromStream(...)
, If strict
is false
, need to support it and raw strings etc.
case 0: | ||
default: | ||
FC_THROW_EXCEPTION( parse_error_exception, "Unexpected char '${c}' in \"${s}\"", | ||
("c", c)("s", stringFromToken(in)) ); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
How about '\'
? According to other code, unquoted strings are allowed in non-strict mode.
@@ -188,18 +190,17 @@ namespace fc | |||
continue; | |||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So ',' can be omitted, e.g. replaced by spaces?
And allow/ignore something like , , ,,,
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Noticed that too. Question is, how much of the original behaviour do we want to change? (Same for other comments above.)
src/io/json.cpp
Outdated
@@ -276,6 +290,7 @@ namespace fc | |||
if (dot) | |||
FC_THROW_EXCEPTION(parse_error_exception, "Can't parse a number with two decimal places"); | |||
dot = true; | |||
[[fallthrough]]; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This attribute is since C++17. I heard Visual Studio doesn't support it but will generate an error (I didn't verify).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oh, I see. Unknown attributes are to be ignored - but only since C++17. :-/
@@ -299,16 +314,20 @@ namespace fc | |||
} | |||
} | |||
catch (fc::eof_exception&) | |||
{ | |||
{ // EOF ends the loop |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
'\0' will ends the loop as well, but hasn't been handled.
E.G. if the string is "-\0[whatever]"
, ss.str()
would be "-"
, so it wouldn't get caught by the "obviously wrong things" check below, finally an exception will be thrown on return to_int64(str);
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, but the same is true for "-[whatever]".
The logic here is: a number is a sequence of digits 0-9, possibly separated once by a dot, and possibly prefixed with a single dash. It doesn't matter if the [whatever] sequence starts with a \0 or something else.
Will add "-" to the list of obviously wrong things.
src/io/json.cpp
Outdated
if( format == json::stringify_large_ints_and_doubles && | ||
i > 0xffffffff ) | ||
v.as_int64() > 0xffffffff ) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do we need to quote it if v.as_int64() < -(int64_t)0xffffffff
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think we should.
@@ -616,27 +590,19 @@ namespace fc | |||
os << "null"; | |||
return; | |||
case variant::int64_type: | |||
{ | |||
int64_t i = v.as_int64(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why change this?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Style, mostly.
IMO these blocks are clumsy, and they're only required so you can declare the "i" variable within the case.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks good.
src/io/json.cpp
Outdated
if( format == json::stringify_large_ints_and_doubles && | ||
i > 0xffffffff ) | ||
( v.as_int64() > 0xffffffff || v.as_int64() < -int64_t(0xffffffff) ) ) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actually I think the range should be [-0x7fffffff, 0x7fffffff]
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
AFAIK the reason for this is the number representation in some scripting languages like JavaScript, which is based on IEEE doubles with 52 bits of precision. 2^32-1 should be safe, as well as -(2^32-1).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
... unless doing bit-shifting.
https://stackoverflow.com/questions/307179/what-is-javascripts-highest-integer-value-that-a-number-can-go-to-without-losin
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The string representation will not enable bit shifting on large integers either.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The string representation will not enable bit shifting on large integers either.
True, but the point is, if it represents as a number, it should enable bit shifting, so 2^31 -1 is the max safe number.
@pmconrad |
{ | ||
FC_ASSERT( max_depth > 0, "Too many nested objects!" ); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There is an issue related to this, although not necessarily caused by it. For example, among this code:
object o( a_nested_object );
variant a;
try {
to_stream( nested_object, a );
} FC_CAPTURE_AND_RETHROW ( (o) );
FC_CAPTURE_AND_RETHROW ();
will try to jsonify o
which is the nested object, so it will throw another exception.
We need to carefully check all catch
es and make sure they don't throw again.
… string.hpp), added handling of recursion errors
@pmconrad something is broken. Unable to make witness_node. Maybe related to the code handling '$' in
|
Sorry, didn't test that. |
No description provided.