Skip to content
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

Add assertion if nullptr is passed to parse function #3593

Merged
merged 14 commits into from
Jul 22, 2022
Merged
4 changes: 4 additions & 0 deletions docs/mkdocs/docs/api/basic_json/accept.md
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,10 @@ Whether the input is valid JSON.

Strong guarantee: if an exception is thrown, there are no changes in the JSON value.

## Exceptions

Throws [`parse_error.116`](../../home/exceptions.md#jsonexceptionparse_error116) if passed `#!cpp FILE` pointer is `#!cpp nullptr`.
nlohmann marked this conversation as resolved.
Show resolved Hide resolved

## Complexity

Linear in the length of the input. The parser is a predictive LL(1) parser.
Expand Down
8 changes: 8 additions & 0 deletions docs/mkdocs/docs/api/basic_json/parse.md
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,14 @@ Deserialized JSON value; in case of a parse error and `allow_exceptions` set to

Strong guarantee: if an exception is thrown, there are no changes in the JSON value.

## Exceptions

- Throws [`parse_error.101`](../../home/exceptions.md#jsonexceptionparse_error101) in case of an unexpected token.
- Throws [`parse_error.102`](../../home/exceptions.md#jsonexceptionparse_error102) if to_unicode fails or surrogate
error.
- Throws [`parse_error.103`](../../home/exceptions.md#jsonexceptionparse_error103) if to_unicode fails.
- Throws [`parse_error.116`](../../home/exceptions.md#jsonexceptionparse_error116) if passed `#!cpp FILE` pointer is `#!cpp nullptr`.

## Complexity

Linear in the length of the input. The parser is a predictive LL(1) parser. The complexity can be higher if the parser
Expand Down
10 changes: 10 additions & 0 deletions docs/mkdocs/docs/home/exceptions.md
Original file line number Diff line number Diff line change
Expand Up @@ -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.
nlohmann marked this conversation as resolved.
Show resolved Hide resolved

!!! failure "Example message"

```
[json.exception.parse_error.116] parse error: input file is invalid
```

## Iterator errors

This exception is thrown if iterators passed to a library function do not match
Expand Down
10 changes: 8 additions & 2 deletions include/nlohmann/detail/input/input_adapters.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
#endif // JSON_NO_IO

#include <nlohmann/detail/iterators/iterator_traits.hpp>
#include <nlohmann/detail/exceptions.hpp>
#include <nlohmann/detail/macro_scope.hpp>

namespace nlohmann
Expand All @@ -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, "input file is invalid", nullptr));
}
}

// make class move-only
file_input_adapter(const file_input_adapter&) = delete;
Expand Down
11 changes: 9 additions & 2 deletions single_include/nlohmann/json.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -5909,6 +5909,8 @@ std::size_t hash(const BasicJsonType& j)

// #include <nlohmann/detail/iterators/iterator_traits.hpp>

// #include <nlohmann/detail/exceptions.hpp>

// #include <nlohmann/detail/macro_scope.hpp>


Expand All @@ -5934,9 +5936,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, "input file is invalid", nullptr));
}
}

// make class move-only
file_input_adapter(const file_input_adapter&) = delete;
Expand Down
20 changes: 20 additions & 0 deletions tests/src/unit-deserialization.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -166,6 +166,21 @@ struct SaxEventLoggerExitAfterStartArray : public SaxEventLogger
};
} // namespace

// Passing a NULL pointer to the input adapter violates its NON_NULL attribute which is detected by UBSAN.
// To still test whether exceptions are thrown, we need to exclude these tests from UBSAN which can only
// be done with a function attribute. See
// https://clang.llvm.org/docs/UndefinedBehaviorSanitizer.html#disabling-instrumentation-with-attribute-no-sanitize-undefined
#if defined(__clang__)
__attribute__((no_sanitize("undefined")))
#endif
nlohmann marked this conversation as resolved.
Show resolved Hide resolved
void test_file_exception()
{
std::FILE* f = std::fopen("nonexisting_file", "r"); // NOLINT(cppcoreguidelines-owning-memory)
nlohmann marked this conversation as resolved.
Show resolved Hide resolved
json _;
CHECK_THROWS_WITH_AS(_ = json::parse(f), "[json.exception.parse_error.116] parse error: input file is invalid", json::parse_error&);
CHECK_THROWS_WITH_AS(_ = json::accept(f), "[json.exception.parse_error.116] parse error: input file is invalid", json::parse_error&);
}

TEST_CASE("deserialization")
{
SECTION("successful deserialization")
Expand Down Expand Up @@ -332,6 +347,11 @@ 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*")
{
test_file_exception();
}
}

SECTION("contiguous containers")
Expand Down