diff --git a/test/tool/net/jsontestsuite_fail1_test.lua b/test/tool/net/jsontestsuite_fail1_test.lua index 11ec6f968..00a378d11 100644 --- a/test/tool/net/jsontestsuite_fail1_test.lua +++ b/test/tool/net/jsontestsuite_fail1_test.lua @@ -30,165 +30,266 @@ -- ljson should reject all of them as invalid -- https://github.com/nst/JSONTestSuite/tree/d64aefb55228d9584d3e5b2433f720ea8fd00c82/test_parsing/n_object_no-colon.json -assert(not DecodeJson(' {"a" ')) +val, err = DecodeJson(' {"a" ') +assert(val == nil) +assert(err == "unexpected eof") -- https://github.com/nst/JSONTestSuite/tree/d64aefb55228d9584d3e5b2433f720ea8fd00c82/test_parsing/n_object_missing_value.json -assert(not DecodeJson(' {"a": ')) +val, err = DecodeJson(' {"a": ') +assert(val == nil) +assert(err == "unexpected eof") -- https://github.com/nst/JSONTestSuite/tree/d64aefb55228d9584d3e5b2433f720ea8fd00c82/test_parsing/n_object_missing_key.json -assert(not DecodeJson(' {:"b"} ')) +val, err = DecodeJson(' {:"b"} ') +assert(val == nil) +assert(err == "unexpected ':'") -- https://github.com/nst/JSONTestSuite/tree/d64aefb55228d9584d3e5b2433f720ea8fd00c82/test_parsing/n_object_missing_colon.json -assert(not DecodeJson(' {"a" b} ')) +val, err = DecodeJson(' {"a" b} ') +assert(val == nil) +assert(err == "illegal character") -- https://github.com/nst/JSONTestSuite/tree/d64aefb55228d9584d3e5b2433f720ea8fd00c82/test_parsing/n_object_key_with_single_quotes.json -assert(not DecodeJson(' {key: \'value\'} ')) +val, err = DecodeJson(' {key: \'value\'} ') +assert(val == nil) +assert(err == "illegal character") -- https://github.com/nst/JSONTestSuite/tree/d64aefb55228d9584d3e5b2433f720ea8fd00c82/test_parsing/n_object_garbage_at_end.json -assert(not DecodeJson(' {"a":"a" 123} ')) +val, err = DecodeJson(' {"a":"a" 123} ') +assert(val == nil) +assert(err == "object key must be string") -- https://github.com/nst/JSONTestSuite/tree/d64aefb55228d9584d3e5b2433f720ea8fd00c82/test_parsing/n_object_emoji.json -- (converted to binary for safety) -assert(not DecodeJson(' \x7b\xf0\x9f\x87\xa8\xf0\x9f\x87\xad\x7d ')) +val, err = DecodeJson(' \x7b\xf0\x9f\x87\xa8\xf0\x9f\x87\xad\x7d ') +assert(val == nil) +assert(err == "illegal character") -- https://github.com/nst/JSONTestSuite/tree/d64aefb55228d9584d3e5b2433f720ea8fd00c82/test_parsing/n_object_bracket_key.json -assert(not DecodeJson(' {[: "x"} ')) +val, err = DecodeJson(' {[: "x"} ') +assert(val == nil) +assert(err == "object key must be string") -- https://github.com/nst/JSONTestSuite/tree/d64aefb55228d9584d3e5b2433f720ea8fd00c82/test_parsing/n_number_with_alpha_char.json -assert(not DecodeJson(' [1.8011670033376514H-308] ')) +val, err = DecodeJson(' [1.8011670033376514H-308] ') +assert(val == nil) +assert(err == "illegal character") -- https://github.com/nst/JSONTestSuite/tree/d64aefb55228d9584d3e5b2433f720ea8fd00c82/test_parsing/n_number_with_alpha.json -assert(not DecodeJson(' [1.2a-3] ')) +val, err = DecodeJson(' [1.2a-3] ') +assert(val == nil) +assert(err == "illegal character") -- https://github.com/nst/JSONTestSuite/tree/d64aefb55228d9584d3e5b2433f720ea8fd00c82/test_parsing/n_number_starting_with_dot.json -assert(not DecodeJson(' [.123] ')) +val, err = DecodeJson(' [.123] ') +assert(val == nil) +assert(err == "illegal character") -- https://github.com/nst/JSONTestSuite/tree/d64aefb55228d9584d3e5b2433f720ea8fd00c82/test_parsing/n_number_real_with_invalid_utf8_after_e.json - -- (converted to binary for safety) -assert(not DecodeJson(' \x5b\x31\x65\xe5\x5d ')) +val, err = DecodeJson(" [1e\xe5] ") +assert(val == nil) +assert(err == "bad exponent") -- https://github.com/nst/JSONTestSuite/tree/d64aefb55228d9584d3e5b2433f720ea8fd00c82/test_parsing/n_number_real_garbage_after_e.json -assert(not DecodeJson(' [1ea] ')) +val, err = DecodeJson(' [1ea] ') +assert(val == nil) +assert(err == "bad exponent") -- https://github.com/nst/JSONTestSuite/tree/d64aefb55228d9584d3e5b2433f720ea8fd00c82/test_parsing/n_number_neg_with_garbage_at_end.json -assert(not DecodeJson(' [-1x] ')) +val, err = DecodeJson(' [-1x] ') +assert(val == nil) +assert(err == "illegal character") -- https://github.com/nst/JSONTestSuite/tree/d64aefb55228d9584d3e5b2433f720ea8fd00c82/test_parsing/n_number_neg_real_without_int_part.json -assert(not DecodeJson(' [-.123] ')) +val, err = DecodeJson(' [-.123] ') +assert(val == nil) +assert(err == "bad negative") -- https://github.com/nst/JSONTestSuite/tree/d64aefb55228d9584d3e5b2433f720ea8fd00c82/test_parsing/n_number_minus_sign_with_trailing_garbage.json -assert(not DecodeJson(' [-foo] ')) +val, err = DecodeJson(' [-foo] ') +assert(val == nil) +assert(err == "bad negative") -- https://github.com/nst/JSONTestSuite/tree/d64aefb55228d9584d3e5b2433f720ea8fd00c82/test_parsing/n_number_minus_infinity.json -assert(not DecodeJson(' [-Infinity] ')) +val, err = DecodeJson(' [-Infinity] ') +assert(val == nil) +assert(err == "bad negative") -- https://github.com/nst/JSONTestSuite/tree/d64aefb55228d9584d3e5b2433f720ea8fd00c82/test_parsing/n_number_invalid-utf-8-in-int.json -- (converted to binary for safety) -assert(not DecodeJson(' \x5b\x30\xe5\x5d ')) +val, err = DecodeJson(' \x5b\x30\xe5\x5d ') +assert(val == nil) +assert(err == "illegal character") -- https://github.com/nst/JSONTestSuite/tree/d64aefb55228d9584d3e5b2433f720ea8fd00c82/test_parsing/n_number_invalid-utf-8-in-exponent.json -- (converted to binary for safety) -assert(not DecodeJson(' \x5b\x31\x65\x31\xe5\x5d ')) +val, err = DecodeJson(' \x5b\x31\x65\x31\xe5\x5d ') +assert(val == nil) +assert(err == "illegal character") -- https://github.com/nst/JSONTestSuite/tree/d64aefb55228d9584d3e5b2433f720ea8fd00c82/test_parsing/n_number_invalid-utf-8-in-bigger-int.json -- (converted to binary for safety) -assert(not DecodeJson(' \x5b\x31\x32\x33\xe5\x5d ')) +val, err = DecodeJson(' \x5b\x31\x32\x33\xe5\x5d ') +assert(val == nil) +assert(err == "illegal character") -- https://github.com/nst/JSONTestSuite/tree/d64aefb55228d9584d3e5b2433f720ea8fd00c82/test_parsing/n_number_invalid-negative-real.json -- (converted to binary for safety) -assert(not DecodeJson(' \x5b\x2d\x31\x32\x33\x2e\x31\x32\x33\x66\x6f\x6f\x5d ')) +val, err = DecodeJson(' \x5b\x2d\x31\x32\x33\x2e\x31\x32\x33\x66\x6f\x6f\x5d ') +assert(val == nil) +assert(err == "missing ','") -- https://github.com/nst/JSONTestSuite/tree/d64aefb55228d9584d3e5b2433f720ea8fd00c82/test_parsing/n_number_invalid+-.json -- (converted to binary for safety) -assert(not DecodeJson(' \x5b\x30\x65\x2b\x2d\x31\x5d ')) +val, err = DecodeJson(" [0e+-1] ") +assert(val == nil) +assert(err == "bad exponent") -- https://github.com/nst/JSONTestSuite/tree/d64aefb55228d9584d3e5b2433f720ea8fd00c82/test_parsing/n_number_infinity.json -assert(not DecodeJson(' [Infinity] ')) +val, err = DecodeJson(' [Infinity] ') +assert(val == nil) +assert(err == "illegal character") -- https://github.com/nst/JSONTestSuite/tree/d64aefb55228d9584d3e5b2433f720ea8fd00c82/test_parsing/n_number_hex_2_digits.json -assert(not DecodeJson(' [0x42] ')) +val, err = DecodeJson(' [0x42] ') +assert(val == nil) +assert(err == "illegal character") -- https://github.com/nst/JSONTestSuite/tree/d64aefb55228d9584d3e5b2433f720ea8fd00c82/test_parsing/n_number_hex_1_digit.json -assert(not DecodeJson(' [0x1] ')) +val, err = DecodeJson(' [0x1] ') +assert(val == nil) +assert(err == "illegal character") -- https://github.com/nst/JSONTestSuite/tree/d64aefb55228d9584d3e5b2433f720ea8fd00c82/test_parsing/n_number_expression.json -assert(not DecodeJson(' [1+2] ')) +val, err = DecodeJson(' [1+2] ') +assert(val == nil) +assert(err == "illegal character") -- https://github.com/nst/JSONTestSuite/tree/d64aefb55228d9584d3e5b2433f720ea8fd00c82/test_parsing/n_number_U+FF11_fullwidth_digit_one.json -- (converted to binary for safety) -assert(not DecodeJson(' \x5b\xef\xbc\x91\x5d ')) +val, err = DecodeJson(' \x5b\xef\xbc\x91\x5d ') +assert(val == nil) +assert(err == "illegal character") -- https://github.com/nst/JSONTestSuite/tree/d64aefb55228d9584d3e5b2433f720ea8fd00c82/test_parsing/n_number_NaN.json -assert(not DecodeJson(' [NaN] ')) +val, err = DecodeJson(' [NaN] ') +assert(val == nil) +assert(err == "illegal character") -- https://github.com/nst/JSONTestSuite/tree/d64aefb55228d9584d3e5b2433f720ea8fd00c82/test_parsing/n_number_Inf.json -assert(not DecodeJson(' [Inf] ')) +val, err = DecodeJson(' [Inf] ') +assert(val == nil) +assert(err == "illegal character") -- https://github.com/nst/JSONTestSuite/tree/d64aefb55228d9584d3e5b2433f720ea8fd00c82/test_parsing/n_number_9.e+.json -assert(not DecodeJson(' [9.e+] ')) +val, err = DecodeJson(' [9.e+] ') +assert(val == nil) +assert(err == "bad double") -- https://github.com/nst/JSONTestSuite/tree/d64aefb55228d9584d3e5b2433f720ea8fd00c82/test_parsing/n_number_1eE2.json -assert(not DecodeJson(' [1eE2] ')) +val, err = DecodeJson(' [1eE2] ') +assert(val == nil) +assert(err == "bad exponent") -- https://github.com/nst/JSONTestSuite/tree/d64aefb55228d9584d3e5b2433f720ea8fd00c82/test_parsing/n_number_1.0e.json -assert(not DecodeJson(' [1.0e] ')) +val, err = DecodeJson(' [1.0e] ') +assert(val == nil) +assert(err == "bad exponent") -- https://github.com/nst/JSONTestSuite/tree/d64aefb55228d9584d3e5b2433f720ea8fd00c82/test_parsing/n_number_1.0e-.json -assert(not DecodeJson(' [1.0e-] ')) +val, err = DecodeJson(' [1.0e-] ') +assert(val == nil) +assert(err == "bad exponent") -- https://github.com/nst/JSONTestSuite/tree/d64aefb55228d9584d3e5b2433f720ea8fd00c82/test_parsing/n_number_1.0e+.json -assert(not DecodeJson(' [1.0e+] ')) +val, err = DecodeJson(' [1.0e+] ') +assert(val == nil) +assert(err == "bad exponent") -- https://github.com/nst/JSONTestSuite/tree/d64aefb55228d9584d3e5b2433f720ea8fd00c82/test_parsing/n_number_0e.json -assert(not DecodeJson(' [0e] ')) +val, err = DecodeJson(' [0e] ') +assert(val == nil) +assert(err == "bad exponent") -- https://github.com/nst/JSONTestSuite/tree/d64aefb55228d9584d3e5b2433f720ea8fd00c82/test_parsing/n_number_0e+.json -assert(not DecodeJson(' [0e+] ')) +val, err = DecodeJson(' [0e+] ') +assert(val == nil) +assert(err == "bad exponent") -- https://github.com/nst/JSONTestSuite/tree/d64aefb55228d9584d3e5b2433f720ea8fd00c82/test_parsing/n_number_0_capital_E.json -assert(not DecodeJson(' [0E] ')) +val, err = DecodeJson(' [0E] ') +assert(val == nil) +assert(err == "bad exponent") -- https://github.com/nst/JSONTestSuite/tree/d64aefb55228d9584d3e5b2433f720ea8fd00c82/test_parsing/n_number_0_capital_E+.json -assert(not DecodeJson(' [0E+] ')) +val, err = DecodeJson(' [0E+] ') +assert(val == nil) +assert(err == "bad exponent") -- https://github.com/nst/JSONTestSuite/tree/d64aefb55228d9584d3e5b2433f720ea8fd00c82/test_parsing/n_number_0.3e.json -assert(not DecodeJson(' [0.3e] ')) +val, err = DecodeJson(' [0.3e] ') +assert(val == nil) +assert(err == "bad exponent") -- https://github.com/nst/JSONTestSuite/tree/d64aefb55228d9584d3e5b2433f720ea8fd00c82/test_parsing/n_number_0.3e+.json -assert(not DecodeJson(' [0.3e+] ')) +val, err = DecodeJson(' [0.3e+] ') +assert(val == nil) +assert(err == "bad exponent") -- https://github.com/nst/JSONTestSuite/tree/d64aefb55228d9584d3e5b2433f720ea8fd00c82/test_parsing/n_number_0.1.2.json -assert(not DecodeJson(' [0.1.2] ')) +val, err = DecodeJson(' [0.1.2] ') +assert(val == nil) +assert(err == "illegal character") -- https://github.com/nst/JSONTestSuite/tree/d64aefb55228d9584d3e5b2433f720ea8fd00c82/test_parsing/n_number_.2e-3.json -assert(not DecodeJson(' [.2e-3] ')) +val, err = DecodeJson(' [.2e-3] ') +assert(val == nil) +assert(err == "illegal character") -- https://github.com/nst/JSONTestSuite/tree/d64aefb55228d9584d3e5b2433f720ea8fd00c82/test_parsing/n_number_.-1.json -assert(not DecodeJson(' [.-1] ')) +val, err = DecodeJson(' [.-1] ') +assert(val == nil) +assert(err == "illegal character") -- https://github.com/nst/JSONTestSuite/tree/d64aefb55228d9584d3e5b2433f720ea8fd00c82/test_parsing/n_number_-NaN.json -assert(not DecodeJson(' [-NaN] ')) +val, err = DecodeJson(' [-NaN] ') +assert(val == nil) +assert(err == "bad negative") -- https://github.com/nst/JSONTestSuite/tree/d64aefb55228d9584d3e5b2433f720ea8fd00c82/test_parsing/n_number_-1.0..json -assert(not DecodeJson(' [-1.0.] ')) +val, err = DecodeJson(' [-1.0.] ') +assert(val == nil) +assert(err == "illegal character") -- https://github.com/nst/JSONTestSuite/tree/d64aefb55228d9584d3e5b2433f720ea8fd00c82/test_parsing/n_number_+Inf.json -assert(not DecodeJson(' [+Inf] ')) +val, err = DecodeJson(' [+Inf] ') +assert(val == nil) +assert(err == "illegal character") -- https://github.com/nst/JSONTestSuite/tree/d64aefb55228d9584d3e5b2433f720ea8fd00c82/test_parsing/n_number_+1.json -assert(not DecodeJson(' [+1] ')) +val, err = DecodeJson(' [+1] ') +assert(val == nil) +assert(err == "illegal character") -- https://github.com/nst/JSONTestSuite/tree/d64aefb55228d9584d3e5b2433f720ea8fd00c82/test_parsing/n_number_++.json -assert(not DecodeJson(' [++1234] ')) +val, err = DecodeJson(' [++1234] ') +assert(val == nil) +assert(err == "illegal character") -- https://github.com/nst/JSONTestSuite/tree/d64aefb55228d9584d3e5b2433f720ea8fd00c82/test_parsing/n_incomplete_true.json -assert(not DecodeJson(' [tru] ')) +val, err = DecodeJson(' [tru] ') +assert(val == nil) +assert(err == "illegal character") -- https://github.com/nst/JSONTestSuite/tree/d64aefb55228d9584d3e5b2433f720ea8fd00c82/test_parsing/n_incomplete_null.json -assert(not DecodeJson(' [nul] ')) +val, err = DecodeJson(' [nul] ') +assert(val == nil) +assert(err == "illegal character") -- https://github.com/nst/JSONTestSuite/tree/d64aefb55228d9584d3e5b2433f720ea8fd00c82/test_parsing/n_incomplete_false.json -assert(not DecodeJson(' [fals] ')) +val, err = DecodeJson(' [fals] ') +assert(val == nil) +assert(err == "illegal character") -- https://github.com/nst/JSONTestSuite/tree/d64aefb55228d9584d3e5b2433f720ea8fd00c82/test_parsing/n_array_unclosed_with_object_inside.json assert(not DecodeJson(' [{} ')) @@ -311,3 +412,24 @@ assert(not DecodeJson(' [1 true] ')) -- https://github.com/nst/JSONTestSuite/tree/d64aefb55228d9584d3e5b2433f720ea8fd00c82/test_parsing/n_object_missing_semicolon.json assert(not DecodeJson(' {"a" "b"} ')) + +-- lool +assert(not DecodeJson(' [--2.] ')) + +-- https://github.com/nst/JSONTestSuite/tree/d64aefb55228d9584d3e5b2433f720ea8fd00c82/test_parsing/n_number_real_without_fractional_part.json +assert(not DecodeJson(' [1.] ')) + +-- https://github.com/nst/JSONTestSuite/tree/d64aefb55228d9584d3e5b2433f720ea8fd00c82/test_parsing/n_number_2.e3.json +assert(not DecodeJson(' [2.e3] ')) + +-- https://github.com/nst/JSONTestSuite/tree/d64aefb55228d9584d3e5b2433f720ea8fd00c82/test_parsing/n_number_2.e-3.json +assert(not DecodeJson(' [2.e-3] ')) + +-- https://github.com/nst/JSONTestSuite/tree/d64aefb55228d9584d3e5b2433f720ea8fd00c82/test_parsing/n_number_2.e+3.json +assert(not DecodeJson(' [2.e+3] ')) + +-- https://github.com/nst/JSONTestSuite/tree/d64aefb55228d9584d3e5b2433f720ea8fd00c82/test_parsing/n_number_0.e1.json +assert(not DecodeJson(' [0.e1] ')) + +-- https://github.com/nst/JSONTestSuite/tree/d64aefb55228d9584d3e5b2433f720ea8fd00c82/test_parsing/n_number_-2..json +assert(not DecodeJson(' [-2.] ')) diff --git a/test/tool/net/jsontestsuite_lenient_test.lua b/test/tool/net/jsontestsuite_lenient_test.lua deleted file mode 100644 index 9a9d90bc3..000000000 --- a/test/tool/net/jsontestsuite_lenient_test.lua +++ /dev/null @@ -1,61 +0,0 @@ --- --- Nicolas Seriot's JSONTestSuite --- https://github.com/nst/JSONTestSuite --- commit d64aefb55228d9584d3e5b2433f720ea8fd00c82 --- --- MIT License --- --- Copyright (c) 2016 Nicolas Seriot --- --- Permission is hereby granted, free of charge, to any person obtaining a copy --- of this software and associated documentation files (the "Software"), to deal --- in the Software without restriction, including without limitation the rights --- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell --- copies of the Software, and to permit persons to whom the Software is --- furnished to do so, subject to the following conditions: --- --- The above copyright notice and this permission notice shall be included in all --- copies or substantial portions of the Software. --- --- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR --- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, --- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE --- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER --- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, --- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE --- SOFTWARE. --- - --- [jart] these tests deviate from the expectations of the upstream test --- suite. most of these failures are because we're more permissive --- about the encoding of double exponents and empty double fraction. - --- from fail1.lua --------------------------------------------------------------------------------- - --- https://github.com/nst/JSONTestSuite/tree/d64aefb55228d9584d3e5b2433f720ea8fd00c82/test_parsing/n_number_real_without_fractional_part.json -assert(DecodeJson(' [1.] ')) -assert(EncodeLua(DecodeJson(' [1.] ')) == EncodeLua({1.0})) - --- https://github.com/nst/JSONTestSuite/tree/d64aefb55228d9584d3e5b2433f720ea8fd00c82/test_parsing/n_number_2.e3.json -assert(DecodeJson(' [2.e3] ')) -assert(EncodeLua(DecodeJson(' [2.e3] ')) == '{2000.}') - --- https://github.com/nst/JSONTestSuite/tree/d64aefb55228d9584d3e5b2433f720ea8fd00c82/test_parsing/n_number_2.e-3.json -assert(DecodeJson(' [2.e-3] ')) -assert(EncodeLua(DecodeJson(' [2.e-3] ')) == '{0.002}') - --- https://github.com/nst/JSONTestSuite/tree/d64aefb55228d9584d3e5b2433f720ea8fd00c82/test_parsing/n_number_2.e+3.json -assert(DecodeJson(' [2.e+3] ')) -assert(EncodeLua(DecodeJson(' [2.e+3] ')) == '{2000.}') - --- https://github.com/nst/JSONTestSuite/tree/d64aefb55228d9584d3e5b2433f720ea8fd00c82/test_parsing/n_number_0.e1.json -assert(DecodeJson(' [0.e1] ')) -assert(EncodeLua(DecodeJson(' [0.e1] ')) == '{0.}') - --- https://github.com/nst/JSONTestSuite/tree/d64aefb55228d9584d3e5b2433f720ea8fd00c82/test_parsing/n_number_-2..json -assert(DecodeJson(' [-2.] ')) -assert(EncodeLua(DecodeJson(' [-2.] ')) == '{-2.}') - --- lool -assert(not DecodeJson(' [--2.] ')) diff --git a/test/tool/net/ljson_test.lua b/test/tool/net/ljson_test.lua index 34b615628..dc0873db8 100644 --- a/test/tool/net/ljson_test.lua +++ b/test/tool/net/ljson_test.lua @@ -20,7 +20,7 @@ assert(EncodeLua(assert(DecodeJson[[ [1,3,2] ]])) == '{1, 3, 2}') assert(EncodeLua(assert(DecodeJson[[ {"foo": 2, "bar": 4} ]])) == '{bar=4, foo=2}') assert(EncodeLua(assert(DecodeJson[[ -123 ]])) == '-123') assert(EncodeLua(assert(DecodeJson[[ 1e6 ]])) == '1000000.') -assert(EncodeLua(assert(DecodeJson[[ 1.e-6 ]])) == '0.000001') +assert(EncodeLua(assert(DecodeJson[[ 1e-6 ]])) == '0.000001') assert(EncodeLua(assert(DecodeJson[[ 1e-06 ]])) == '0.000001') assert(EncodeLua(assert(DecodeJson[[ 9.123e6 ]])) == '9123000.') assert(EncodeLua(assert(DecodeJson[[ [{"heh": [1,3,2]}] ]])) == '{{heh={1, 3, 2}}}') diff --git a/third_party/lua/luaencodejsondata.c b/third_party/lua/luaencodejsondata.c index 64dc7f264..8dd4910e4 100644 --- a/third_party/lua/luaencodejsondata.c +++ b/third_party/lua/luaencodejsondata.c @@ -24,6 +24,7 @@ #include "libc/log/rop.h" #include "libc/mem/mem.h" #include "libc/runtime/gc.internal.h" +#include "libc/runtime/stack.h" #include "libc/stdio/append.internal.h" #include "libc/stdio/strlist.internal.h" #include "libc/str/str.h" @@ -93,7 +94,7 @@ static int SerializeArray(lua_State *L, char **buf, struct Serializer *z, size_t i; RETURN_ON_ERROR(appendw(buf, '[')); for (i = 1; i <= tbllen; i++) { - lua_rawgeti(L, -1, i); + lua_rawgeti(L, -1, i); // +2 if (i > 1) RETURN_ON_ERROR(appendw(buf, ',')); RETURN_ON_ERROR(Serialize(L, buf, -1, z, level - 1)); lua_pop(L, 1); @@ -108,8 +109,8 @@ static int SerializeObject(lua_State *L, char **buf, struct Serializer *z, int level) { bool comma = false; RETURN_ON_ERROR(appendw(buf, '{')); - lua_pushnil(L); - while (lua_next(L, -2)) { + lua_pushnil(L); // +2 + while (lua_next(L, -2)) { // +3 if (lua_type(L, -2) == LUA_TSTRING) { if (comma) { RETURN_ON_ERROR(appendw(buf, ',')); @@ -164,9 +165,13 @@ static int SerializeTable(lua_State *L, char **buf, int idx, int rc; bool isarray; lua_Unsigned n; + if ((intptr_t)__builtin_frame_address(0) < GetStackAddr() + PAGESIZE * 2) { + z->reason = "out of stack"; + return -1; + } RETURN_ON_ERROR(rc = LuaPushVisit(&z->visited, lua_topointer(L, idx))); if (!rc) { - lua_pushvalue(L, idx); + lua_pushvalue(L, idx); // +1 if ((n = lua_rawlen(L, -1)) > 0) { isarray = true; } else { @@ -250,7 +255,7 @@ static int Serialize(lua_State *L, char **buf, int idx, struct Serializer *z, int LuaEncodeJsonData(lua_State *L, char **buf, int idx, bool sorted) { int rc, depth = 64; struct Serializer z = {.reason = "out of memory", .sorted = sorted}; - if (lua_checkstack(L, depth * 4)) { + if (lua_checkstack(L, depth * 3 + LUA_MINSTACK)) { rc = Serialize(L, buf, idx, &z, depth); free(z.visited.p); free(z.strbuf); diff --git a/third_party/lua/luaencodeluadata.c b/third_party/lua/luaencodeluadata.c index f361a95b3..b66d3e9ea 100644 --- a/third_party/lua/luaencodeluadata.c +++ b/third_party/lua/luaencodeluadata.c @@ -22,6 +22,7 @@ #include "libc/log/rop.h" #include "libc/math.h" #include "libc/mem/mem.h" +#include "libc/runtime/stack.h" #include "libc/stdio/append.internal.h" #include "libc/stdio/strlist.internal.h" #include "libc/x/x.h" @@ -334,6 +335,11 @@ OnError: static int SerializeTable(lua_State *L, char **buf, int idx, struct Serializer *z, int depth) { int rc; + intptr_t rsp, bot; + if ((intptr_t)__builtin_frame_address(0) < GetStackAddr() + PAGESIZE * 2) { + z->reason = "out of stack"; + return -1; + } RETURN_ON_ERROR(rc = LuaPushVisit(&z->visited, lua_topointer(L, idx))); if (rc) return SerializeOpaque(L, buf, idx, "cyclic"); lua_pushvalue(L, idx); // idx becomes invalid once we change stack @@ -400,7 +406,7 @@ static int Serialize(lua_State *L, char **buf, int idx, struct Serializer *z, int LuaEncodeLuaData(lua_State *L, char **buf, int idx, bool sorted) { int rc, depth = 64; struct Serializer z = {.reason = "out of memory", .sorted = sorted}; - if (lua_checkstack(L, depth * 4)) { + if (lua_checkstack(L, depth * 3 + LUA_MINSTACK)) { rc = Serialize(L, buf, idx, &z, depth); free(z.visited.p); if (rc == -1) { diff --git a/tool/net/help.txt b/tool/net/help.txt index 601a6bee8..8430a92b9 100644 --- a/tool/net/help.txt +++ b/tool/net/help.txt @@ -725,16 +725,12 @@ FUNCTIONS output is valid. Please note that invalid utf-8 could still happen if it's encoded as utf-8. - This parser is lenient about commas and colons. For example - it's permissible to say `DecodeJson('[1 2 3 4]')`. Trailing - commas are allowed. Even prefix commas are allowed. However - it's not recommended that you rely on this behavior, and it - won't round-trip with EncodeJson() currently. - When objects are parsed, your Lua object can't preserve the the original ordering of fields. As such, they'll be sorted by EncodeJson() and may not round-trip with original intent + This parser has perfect conformance with JSONTestSuite. + EncodeJson(value[, options:table]) ├─→ json:str ├─→ true [if useoutput] diff --git a/tool/net/ljson.c b/tool/net/ljson.c index 8a0f3992f..fa1f5ecaf 100644 --- a/tool/net/ljson.c +++ b/tool/net/ljson.c @@ -21,6 +21,7 @@ #include "libc/intrin/kprintf.h" #include "libc/log/check.h" #include "libc/log/log.h" +#include "libc/runtime/stack.h" #include "libc/str/str.h" #include "libc/str/tpenc.h" #include "libc/str/utf16.h" @@ -31,27 +32,28 @@ #include "third_party/lua/lua.h" #include "tool/net/ljson.h" -#define AFTER_VALUE 0x01u -#define ARRAY_SINGLE 0x02u -#define ARRAY_END 0x04u -#define OBJECT_KEY 0x10u -#define OBJECT_VAL 0x20u -#define OBJECT_END 0x40u - -#define TOP_LEVEL 64 +#define KEY 1 +#define COMMA 2 +#define COLON 4 +#define ARRAY 8 +#define OBJECT 16 +#define DEPTH 64 static struct DecodeJson Parse(struct lua_State *L, const char *p, const char *e, int context, int depth) { long x; char w[4]; - const char *a; luaL_Buffer b; - const char *reason; struct DecodeJson r; + const char *a, *reason; int A, B, C, D, c, d, i, u; if (UNLIKELY(!depth)) { return (struct DecodeJson){-1, "maximum depth exceeded"}; } + if (UNLIKELY((intptr_t)__builtin_frame_address(0) < + GetStackAddr() + PAGESIZE * 2)) { + return (struct DecodeJson){-1, "out of stack"}; + } for (a = p, d = +1; p < e;) { switch ((c = *p++ & 255)) { case ' ': // spaces @@ -62,7 +64,7 @@ static struct DecodeJson Parse(struct lua_State *L, const char *p, break; case ',': // present in list and object - if (0 != (context & AFTER_VALUE)) { + if (context & COMMA) { context = 0; a = p; break; @@ -71,7 +73,7 @@ static struct DecodeJson Parse(struct lua_State *L, const char *p, } case ':': // present only in object after key - if (0 != (context & OBJECT_VAL)) { + if (context & COLON) { context = 0; a = p; break; @@ -80,8 +82,7 @@ static struct DecodeJson Parse(struct lua_State *L, const char *p, } case 'n': // null - if (UNLIKELY(0 != (context & OBJECT_KEY))) goto BadObjectKey; - if (UNLIKELY(0 != (context & (OBJECT_VAL | AFTER_VALUE)))) goto MissingPunctuation; + if (context & (KEY | COLON | COMMA)) goto OnColonCommaKey; if (p + 3 <= e && READ32LE(p - 1) == READ32LE("null")) { lua_pushnil(L); return (struct DecodeJson){1, p + 3}; @@ -90,8 +91,7 @@ static struct DecodeJson Parse(struct lua_State *L, const char *p, } case 'f': // false - if (UNLIKELY(0 != (context & OBJECT_KEY))) goto BadObjectKey; - if (UNLIKELY(0 != (context & (OBJECT_VAL | AFTER_VALUE)))) goto MissingPunctuation; + if (context & (KEY | COLON | COMMA)) goto OnColonCommaKey; if (p + 4 <= e && READ32LE(p) == READ32LE("alse")) { lua_pushboolean(L, false); return (struct DecodeJson){1, p + 4}; @@ -100,8 +100,7 @@ static struct DecodeJson Parse(struct lua_State *L, const char *p, } case 't': // true - if (UNLIKELY(0 != (context & OBJECT_KEY))) goto BadObjectKey; - if (UNLIKELY(0 != (context & (OBJECT_VAL | AFTER_VALUE)))) goto MissingPunctuation; + if (context & (KEY | COLON | COMMA)) goto OnColonCommaKey; if (p + 3 <= e && READ32LE(p - 1) == READ32LE("true")) { lua_pushboolean(L, true); return (struct DecodeJson){1, p + 3}; @@ -109,14 +108,21 @@ static struct DecodeJson Parse(struct lua_State *L, const char *p, goto IllegalCharacter; } + default: + IllegalCharacter: + return (struct DecodeJson){-1, "illegal character"}; + OnColonCommaKey: + if (context & KEY) goto BadObjectKey; + OnColonComma: + if (context & COLON) goto MissingColon; + return (struct DecodeJson){-1, "missing ','"}; + MissingColon: + return (struct DecodeJson){-1, "missing ':'"}; BadObjectKey: return (struct DecodeJson){-1, "object key must be string"}; - MissingPunctuation: - return (struct DecodeJson){-1, "missing ',' or ':'"}; case '-': // negative - if (UNLIKELY(0 != (context & OBJECT_KEY))) goto BadObjectKey; - if (UNLIKELY(0 != (context & (OBJECT_VAL | AFTER_VALUE)))) goto MissingPunctuation; + if (context & (COLON | COMMA | KEY)) goto OnColonCommaKey; if (p < e && isdigit(*p)) { d = -1; break; @@ -125,10 +131,14 @@ static struct DecodeJson Parse(struct lua_State *L, const char *p, } case '0': // zero or number - if (UNLIKELY(0 != (context & OBJECT_KEY))) goto BadObjectKey; - if (UNLIKELY(0 != (context & (OBJECT_VAL | AFTER_VALUE)))) goto MissingPunctuation; + if (context & (COLON | COMMA | KEY)) goto OnColonCommaKey; if (p < e) { - if ((*p == '.' || *p == 'e' || *p == 'E')) { + if (*p == '.') { + if (p + 1 == e || !isdigit(p[1])) { + return (struct DecodeJson){-1, "bad double"}; + } + goto UseDubble; + } else if (*p == 'e' || *p == 'E') { goto UseDubble; } else if (isdigit(*p)) { return (struct DecodeJson){-1, "unexpected octal"}; @@ -138,8 +148,7 @@ static struct DecodeJson Parse(struct lua_State *L, const char *p, return (struct DecodeJson){1, p}; case '1' ... '9': // integer - if (UNLIKELY(0 != (context & OBJECT_KEY))) goto BadObjectKey; - if (UNLIKELY(0 != (context & (OBJECT_VAL | AFTER_VALUE)))) goto MissingPunctuation; + if (context & (COLON | COMMA | KEY)) goto OnColonCommaKey; for (x = (c - '0') * d; p < e; ++p) { c = *p & 255; if (isdigit(c)) { @@ -147,7 +156,12 @@ static struct DecodeJson Parse(struct lua_State *L, const char *p, __builtin_add_overflow(x, (c - '0') * d, &x)) { goto UseDubble; } - } else if (c == '.' || c == 'e' || c == 'E') { + } else if (c == '.') { + if (p + 1 == e || !isdigit(p[1])) { + return (struct DecodeJson){-1, "bad double"}; + } + goto UseDubble; + } else if (c == 'e' || c == 'E') { goto UseDubble; } else { break; @@ -159,15 +173,16 @@ static struct DecodeJson Parse(struct lua_State *L, const char *p, UseDubble: // number lua_pushnumber(L, StringToDouble(a, e - a, &c)); DCHECK(c > 0, "paranoid avoiding infinite loop"); + if (a + c < e && (a[c] == 'e' || a[c] == 'E')) { + return (struct DecodeJson){-1, "bad exponent"}; + } return (struct DecodeJson){1, a + c}; case '[': // Array - if (UNLIKELY(0 != (context & OBJECT_KEY))) goto BadObjectKey; - if (UNLIKELY(0 != (context & (OBJECT_VAL | AFTER_VALUE)))) goto MissingPunctuation; - lua_newtable(L); - i = 0; - r = Parse(L, p, e, ARRAY_SINGLE | ARRAY_END, depth - 1); - for (;;) { + if (context & (COLON | COMMA | KEY)) goto OnColonCommaKey; + lua_newtable(L); // +1 + for (context = ARRAY, i = 0;;) { + r = Parse(L, p, e, context, depth - 1); // +2 if (UNLIKELY(r.rc == -1)) { lua_pop(L, 1); return r; @@ -177,44 +192,44 @@ static struct DecodeJson Parse(struct lua_State *L, const char *p, break; } lua_rawseti(L, -2, i++ + 1); - r = Parse(L, p, e, AFTER_VALUE | ARRAY_END, depth - 1); + context = ARRAY | COMMA; } if (!i) { // we need this kludge so `[]` won't round-trip as `{}` - lua_pushboolean(L, false); + lua_pushboolean(L, false); // +2 lua_rawseti(L, -2, 0); } return (struct DecodeJson){1, p}; case ']': - if (0 != (context & ARRAY_END)) { + if (context & ARRAY) { return (struct DecodeJson){0, p}; } else { return (struct DecodeJson){-1, "unexpected ']'"}; } case '}': - if (0 != (context & OBJECT_END)) { + if (context & OBJECT) { return (struct DecodeJson){0, p}; } else { return (struct DecodeJson){-1, "unexpected '}'"}; } case '{': // Object - if (UNLIKELY(0 != (context & OBJECT_KEY))) goto BadObjectKey; - if (UNLIKELY(0 != (context & (OBJECT_VAL | AFTER_VALUE)))) goto MissingPunctuation; - lua_newtable(L); - r = Parse(L, p, e, OBJECT_KEY | OBJECT_END, depth - 1); + if (context & (COLON | COMMA | KEY)) goto OnColonCommaKey; + lua_newtable(L); // +1 + context = KEY | OBJECT; for (;;) { + r = Parse(L, p, e, context, depth - 1); // +2 if (r.rc == -1) { lua_pop(L, 1); return r; } p = r.p; if (!r.rc) { - break; + return (struct DecodeJson){1, p}; } - r = Parse(L, p, e, OBJECT_VAL, depth - 1); + r = Parse(L, p, e, COLON, depth - 1); // +3 if (r.rc == -1) { lua_pop(L, 2); return r; @@ -225,12 +240,11 @@ static struct DecodeJson Parse(struct lua_State *L, const char *p, } p = r.p; lua_settable(L, -3); - r = Parse(L, p, e, OBJECT_KEY | AFTER_VALUE | OBJECT_END, depth - 1); + context = KEY | COMMA | OBJECT; } - return (struct DecodeJson){1, p}; case '"': // string - if (UNLIKELY(0 != (context & (OBJECT_VAL | AFTER_VALUE)))) goto MissingPunctuation; + if (context & (COLON | COMMA)) goto OnColonComma; luaL_buffinit(L, &b); for (;;) { if (UNLIKELY(p >= e)) { @@ -252,7 +266,7 @@ static struct DecodeJson Parse(struct lua_State *L, const char *p, } continue; HandleEscape: - if (UNLIKELY(p >= e)) { + if (p >= e) { goto UnexpectedEofString; } switch ((c = *p++ & 255)) { @@ -331,7 +345,7 @@ static struct DecodeJson Parse(struct lua_State *L, const char *p, w[1] = 0200 | (c & 077); i = 2; } else if (c <= 0xffff) { - if (UNLIKELY(IsSurrogate(c))) { + if (IsSurrogate(c)) { ReplacementCharacter: c = 0xfffd; } @@ -368,13 +382,9 @@ static struct DecodeJson Parse(struct lua_State *L, const char *p, luaL_pushresultsize(&b, 0); lua_pop(L, 1); return (struct DecodeJson){-1, reason}; - - default: - IllegalCharacter: - return (struct DecodeJson){-1, "illegal character"}; } } - if (UNLIKELY(depth == TOP_LEVEL)) { + if (depth == DEPTH) { return (struct DecodeJson){0, 0}; } else { return (struct DecodeJson){-1, "unexpected eof"}; @@ -405,10 +415,9 @@ static struct DecodeJson Parse(struct lua_State *L, const char *p, * @return r.p is string describing error if `rc < 0` */ struct DecodeJson DecodeJson(struct lua_State *L, const char *p, size_t n) { - int depth = TOP_LEVEL; if (n == -1) n = p ? strlen(p) : 0; - if (lua_checkstack(L, depth * 4)) { - return Parse(L, p, p + n, 0, depth); + if (lua_checkstack(L, DEPTH * 3 + LUA_MINSTACK)) { + return Parse(L, p, p + n, 0, DEPTH); } else { return (struct DecodeJson){-1, "can't set stack depth"}; }