mirror of
https://github.com/nlohmann/json.git
synced 2026-10-03 13:10:33 +00:00
Recover from parse errors when parse_error() returns true (#3989)
The return value of json_sax::parse_error() was documented both as "must return false" and as "whether the parsing should continue", and the code just passed it on. For JSON text, parsing stopped anyway, but sax_parse() could report success for invalid input. The binary readers read on after the error, looping forever on a CBOR indefinite-length array without its end. Now false stops parsing, and true recovers from the error: - JSON text is repaired with the smallest local edit (insert a missing ',' or ':', remove a stray token, keep the readable part of a broken string or number, null for a value that cannot be read, close the innermost container at a wrong closing bracket and all of them at the end of the input), and parsing continues. The SAX events stay balanced, every key is followed by exactly one value, and each token is reported at most once. - The binary formats cannot resynchronize, so they stop, but complete the value read so far. sax_parse() returns false after any error. parse(), accept(), and the from_*() functions never recover and compile to the same code as before. Supersedes #4522. Signed-off-by: Niels Lohmann <mail@nlohmann.me>
This commit is contained in:
@@ -4979,6 +4979,26 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
|
||||
return parser(i.get(), nullptr, false, ignore_comments, ignore_trailing_commas, true).accept(true);
|
||||
}
|
||||
|
||||
private:
|
||||
/// read a binary format and pass it to a SAX parser; if the SAX parser
|
||||
/// asks to recover from an error, the value read so far is completed
|
||||
/// (see detail::json_sax_salvager and #3989)
|
||||
template<typename InputAdapterType, typename SAX>
|
||||
static bool sax_parse_binary(InputAdapterType ia, SAX* sax,
|
||||
const input_format_t format, const bool strict)
|
||||
{
|
||||
(void)detail::is_sax_static_asserts<SAX, basic_json> {};
|
||||
using salvager_t = detail::json_sax_salvager<basic_json, SAX>;
|
||||
salvager_t salvager(sax);
|
||||
const bool result = detail::binary_reader<basic_json, InputAdapterType, salvager_t>(std::move(ia), format).sax_parse(format, &salvager, strict);
|
||||
if (!result)
|
||||
{
|
||||
salvager.close_open_containers();
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
public:
|
||||
/// @brief generate SAX events
|
||||
/// @sa https://json.nlohmann.me/api/basic_json/sax_parse/
|
||||
template <typename InputType, typename SAX>
|
||||
@@ -4992,7 +5012,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
|
||||
auto ia = detail::input_adapter(std::forward<InputType>(i));
|
||||
return format == input_format_t::json
|
||||
? parser(std::move(ia), nullptr, true, ignore_comments, ignore_trailing_commas).sax_parse(sax, strict)
|
||||
: detail::binary_reader<basic_json, decltype(ia), SAX>(std::move(ia), format).sax_parse(format, sax, strict);
|
||||
: sax_parse_binary(std::move(ia), sax, format, strict);
|
||||
}
|
||||
|
||||
/// @brief generate SAX events (iterator pair, or iterator+sentinel pair for C++20 ranges support)
|
||||
@@ -5009,7 +5029,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
|
||||
auto ia = detail::input_adapter(std::move(first), std::move(last));
|
||||
return format == input_format_t::json
|
||||
? parser(std::move(ia), nullptr, true, ignore_comments, ignore_trailing_commas).sax_parse(sax, strict)
|
||||
: detail::binary_reader<basic_json, decltype(ia), SAX>(std::move(ia), format).sax_parse(format, sax, strict);
|
||||
: sax_parse_binary(std::move(ia), sax, format, strict);
|
||||
}
|
||||
|
||||
/// @brief generate SAX events
|
||||
@@ -5031,7 +5051,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
|
||||
// NOLINTNEXTLINE(hicpp-move-const-arg,performance-move-const-arg)
|
||||
? parser(std::move(ia), nullptr, true, ignore_comments, ignore_trailing_commas).sax_parse(sax, strict)
|
||||
// NOLINTNEXTLINE(hicpp-move-const-arg,performance-move-const-arg)
|
||||
: detail::binary_reader<basic_json, decltype(ia), SAX>(std::move(ia), format).sax_parse(format, sax, strict);
|
||||
: sax_parse_binary(std::move(ia), sax, format, strict);
|
||||
}
|
||||
#ifndef JSON_NO_IO
|
||||
/// @brief deserialize from stream
|
||||
|
||||
Reference in New Issue
Block a user