From b661022ccd03baae65860964305147bafe62ad1f Mon Sep 17 00:00:00 2001 From: Niels Lohmann Date: Wed, 20 Jul 2022 13:09:36 +0200 Subject: [PATCH] :boom: throw exception if nullptr is passed to parse function Addresses #3584 --- docs/mkdocs/docs/api/basic_json/parse.md | 2 +- docs/mkdocs/docs/home/exceptions.md | 10 ++++++++++ include/nlohmann/detail/input/input_adapters.hpp | 12 +++++++++--- single_include/nlohmann/json.hpp | 12 +++++++++--- tests/src/unit-deserialization.cpp | 6 ++++++ 5 files changed, 35 insertions(+), 7 deletions(-) diff --git a/docs/mkdocs/docs/api/basic_json/parse.md b/docs/mkdocs/docs/api/basic_json/parse.md index 92808cd6b..0bfae1916 100644 --- a/docs/mkdocs/docs/api/basic_json/parse.md +++ b/docs/mkdocs/docs/api/basic_json/parse.md @@ -28,7 +28,7 @@ static basic_json parse(IteratorType first, IteratorType last, : A compatible input, for instance: - an `std::istream` object - - a `FILE` pointer + - a `FILE` pointer (will throw [json.exception.parse_error.116](../../home/exceptions.md#jsonexceptionparse_error116) if passed pointer is `#!cpp nullptr`) - a C-style array of characters - a pointer to a null-terminated string of single byte characters - a `std::string` diff --git a/docs/mkdocs/docs/home/exceptions.md b/docs/mkdocs/docs/home/exceptions.md index c9885ae6f..8efad510e 100644 --- a/docs/mkdocs/docs/home/exceptions.md +++ b/docs/mkdocs/docs/home/exceptions.md @@ -354,6 +354,16 @@ A UBJSON high-precision number could not be parsed. [json.exception.parse_error.115] parse error at byte 5: syntax error while parsing UBJSON high-precision number: invalid number text: 1A ``` +### json.exception.parse_error.116 + +A `#!cpp FILE*` pointer passed to the [parse](../api/basic_json/parse.md) function is `#!cpp nullptr`; that is, a previous call to `#!cpp std::fopen` failed. + +!!! failure "Example message" + + ``` + [json.exception.parse_error.116] parse error: input file is invalid: No such file or directory + ``` + ## Iterator errors This exception is thrown if iterators passed to a library function do not match diff --git a/include/nlohmann/detail/input/input_adapters.hpp b/include/nlohmann/detail/input/input_adapters.hpp index 2bc49aa2e..802746b06 100644 --- a/include/nlohmann/detail/input/input_adapters.hpp +++ b/include/nlohmann/detail/input/input_adapters.hpp @@ -9,8 +9,9 @@ #pragma once #include // array +#include // errno #include // size_t -#include // strlen +#include // strlen, strerror #include // begin, end, iterator_traits, random_access_iterator_tag, distance, next #include // shared_ptr, make_shared, addressof #include // accumulate @@ -48,9 +49,14 @@ class file_input_adapter using char_type = char; JSON_HEDLEY_NON_NULL(2) - explicit file_input_adapter(std::FILE* f) noexcept + explicit file_input_adapter(std::FILE* f) : m_file(f) - {} + { + if (m_file == nullptr) + { + JSON_THROW(parse_error::create(116, 0, detail::concat("input file is invalid: ", reinterpret_cast(std::strerror(errno))), nullptr)); + } + } // make class move-only file_input_adapter(const file_input_adapter&) = delete; diff --git a/single_include/nlohmann/json.hpp b/single_include/nlohmann/json.hpp index cc5562d06..25908710b 100644 --- a/single_include/nlohmann/json.hpp +++ b/single_include/nlohmann/json.hpp @@ -5893,8 +5893,9 @@ std::size_t hash(const BasicJsonType& j) #include // array +#include // errno #include // size_t -#include // strlen +#include // strlen, strerror #include // begin, end, iterator_traits, random_access_iterator_tag, distance, next #include // shared_ptr, make_shared, addressof #include // accumulate @@ -5934,9 +5935,14 @@ class file_input_adapter using char_type = char; JSON_HEDLEY_NON_NULL(2) - explicit file_input_adapter(std::FILE* f) noexcept + explicit file_input_adapter(std::FILE* f) : m_file(f) - {} + { + if (m_file == nullptr) + { + JSON_THROW(parse_error::create(116, 0, detail::concat("input file is invalid: ", reinterpret_cast(std::strerror(errno))), nullptr)); + } + } // make class move-only file_input_adapter(const file_input_adapter&) = delete; diff --git a/tests/src/unit-deserialization.cpp b/tests/src/unit-deserialization.cpp index ef2a67f5c..7018dc0f2 100644 --- a/tests/src/unit-deserialization.cpp +++ b/tests/src/unit-deserialization.cpp @@ -332,6 +332,12 @@ TEST_CASE("deserialization") { CHECK_THROWS_WITH_AS("[\"foo\",1,2,3,false,{\"one\":1}"_json, "[json.exception.parse_error.101] parse error at line 1, column 29: syntax error while parsing array - unexpected end of input; expected ']'", json::parse_error&); } + + SECTION("FILE*") + { + std::FILE* f = std::fopen("nonexisting_file", "r"); // NOTLINT(cppcoreguidelines-owning-memory) + CHECK_THROWS_WITH_AS(json::parse(f), "[json.exception.parse_error.116] parse error: input file is invalid: No such file or directory", json::parse_error&); + } } SECTION("contiguous containers")