/src/glaze/fuzzing/json_roundtrip_string.cpp
Line | Count | Source |
1 | | #include <cassert> |
2 | | #include <cmath> |
3 | | #include <cstddef> |
4 | | #include <cstdint> |
5 | | #include <cstring> |
6 | | #include <glaze/glaze.hpp> |
7 | | #include <vector> |
8 | | |
9 | | struct S |
10 | | { |
11 | | std::string value{}; |
12 | | }; |
13 | | |
14 | | void test(const uint8_t* Data, size_t Size) |
15 | 679 | { |
16 | 679 | S s{{Data, Data + Size}}; |
17 | | |
18 | | // note - glaze does not escape control characters. see https://github.com/stephenberry/glaze/issues/812 |
19 | | |
20 | | // replace control characters with space |
21 | 51.8M | for (auto& c : s.value) { |
22 | | // std::iscntrl has undefined behavior for negative values, so widen through unsigned char. |
23 | 51.8M | if (std::iscntrl(static_cast<unsigned char>(c)) && c != '\b' && c != '\f' && c != '\n' && c != '\r' && |
24 | 9.45M | c != '\t') { |
25 | 9.04M | c = ' '; |
26 | 9.04M | } |
27 | 51.8M | } |
28 | | |
29 | | // Control characters are ASCII, so the substitution above cannot change whether the string is |
30 | | // well formed UTF-8. |
31 | 679 | const bool well_formed = glz::validate_utf8(s.value.data(), s.value.size()); |
32 | | |
33 | 679 | auto str = glz::write_json(s).value_or(std::string{}); |
34 | 679 | auto restored = glz::read_json<S>(str); |
35 | | |
36 | 679 | if (well_formed) { |
37 | 396 | assert(restored); |
38 | 396 | assert(restored.value().value == s.value); |
39 | 396 | } |
40 | 283 | else { |
41 | | // Writing is deliberately not validated while reading always is, so a std::string holding |
42 | | // malformed UTF-8 serializes and then fails to parse back. Assert that asymmetry rather than |
43 | | // skipping these inputs, so the round trip contract stays pinned in both directions. |
44 | 283 | assert(!restored); |
45 | 283 | assert(restored.error().ec == glz::error_code::invalid_utf8); |
46 | 283 | } |
47 | 679 | } |
48 | | |
49 | | extern "C" int LLVMFuzzerTestOneInput(const uint8_t* Data, size_t Size) |
50 | 36.5k | { |
51 | 36.5k | test(Data, Size); |
52 | 36.5k | return 0; |
53 | 36.5k | } |