| // __ _____ _____ _____ | |
| // __| | __| | | | JSON for Modern C++ (supporting code) | |
| // | | |__ | | | | | | version 3.12.0 | |
| // |_____|_____|_____|_|___| https://github.com/nlohmann/json | |
| // | |
| // SPDX-FileCopyrightText: 2013-2026 Niels Lohmann <https://nlohmann.me> | |
| // SPDX-License-Identifier: MIT | |
| /* | |
| This file implements a parser test suitable for fuzz testing. Given a byte | |
| array data, it performs the following steps: | |
| - j0 = from_bon8(data, allow_exceptions = false) | |
| - j1 = from_bon8(data) | |
| - assert(j0 is discarded if parsing j1 fails, and j0 == j1 otherwise) | |
| - vec = to_bon8(j1) | |
| - j2 = from_bon8(vec) | |
| - assert(to_bon8(j2) == vec) | |
| Finally, it reads the data from a stream, a non-contiguous iterator range, and | |
| a FILE*, which read byte by byte, and checks that each gives the same value or | |
| error (id, message, byte position) as the pointer range, which takes the bulk | |
| fast paths (see check_input_adapters()). | |
| The provided function `LLVMFuzzerTestOneInput` can be used in different fuzzer | |
| drivers. | |
| */ | |
| #include "fuzzer_common.hpp" | |
| namespace | |
| { | |
| // json::from_bon8 for check_input_adapters() | |
| struct read_bon8 | |
| { | |
| template<typename... Args> | |
| json operator()(Args&& ... args) const | |
| { | |
| return json::from_bon8(std::forward<Args>(args)...); | |
| } | |
| }; | |
| } // namespace | |
| // see http://llvm.org/docs/LibFuzzer.html | |
| extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) | |
| { | |
| std::vector<uint8_t> const vec1(data, data + size); | |
| // step 0: parse input without exceptions | |
| bool noexcept_threw = false; | |
| json const j_noexcept = parse_without_exceptions([&] { return json::from_bon8(vec1, true, false); }, noexcept_threw); | |
| // whether step 1 succeeded; if not, the catch blocks below check that | |
| // step 0 failed, too | |
| bool parsed = false; | |
| try | |
| { | |
| // step 1: parse input | |
| json const j1 = json::from_bon8(vec1); | |
| parsed = true; | |
| // without exceptions, the same input must give the same value | |
| assert(!noexcept_threw && !j_noexcept.is_discarded() && same_value(j_noexcept, j1)); | |
| try | |
| { | |
| // step 2: round trip | |
| std::vector<uint8_t> const vec2 = json::to_bon8(j1); | |
| // parse serialization | |
| json const j2 = json::from_bon8(vec2); | |
| // serializations must match | |
| assert(json::to_bon8(j2) == vec2); | |
| } | |
| catch (const json::parse_error&) | |
| { | |
| // parsing a BON8 serialization must not fail | |
| assert(false); | |
| } | |
| } | |
| catch (const json::parse_error&) | |
| { | |
| // parse errors are ok, because input may be random bytes | |
| assert(parsed || noexcept_threw || j_noexcept.is_discarded()); | |
| } | |
| catch (const json::type_error&) | |
| { | |
| // type errors can occur during parsing, too | |
| assert(parsed || noexcept_threw || j_noexcept.is_discarded()); | |
| } | |
| catch (const json::out_of_range&) | |
| { | |
| // out of range errors may happen if provided sizes are excessive | |
| assert(parsed || noexcept_threw || j_noexcept.is_discarded()); | |
| } | |
| // step 3: the other input adapters must read the data alike | |
| check_input_adapters(data, size, read_bon8()); | |
| // return 0 - non-zero return values are reserved for future use | |
| return 0; | |
| } |