]>
Commit | Line | Data |
---|---|---|
f67539c2 TL |
1 | // Copyright (c) 2019, Paul Dreik |
2 | // License: see LICENSE.rst in the fmt root directory | |
3 | #include <fmt/format.h> | |
4 | #include <fmt/printf.h> | |
5 | #include <cstdint> | |
6 | #include <stdexcept> | |
7 | ||
8 | #include "fuzzer_common.h" | |
9 | ||
10 | using fmt_fuzzer::Nfixed; | |
11 | ||
12 | template <typename Item1, typename Item2> | |
13 | void invoke_fmt(const uint8_t* Data, size_t Size) { | |
14 | constexpr auto N1 = sizeof(Item1); | |
15 | constexpr auto N2 = sizeof(Item2); | |
16 | static_assert(N1 <= Nfixed, "size1 exceeded"); | |
17 | static_assert(N2 <= Nfixed, "size2 exceeded"); | |
18 | if (Size <= Nfixed + Nfixed) { | |
19 | return; | |
20 | } | |
21 | Item1 item1 = fmt_fuzzer::assignFromBuf<Item1>(Data); | |
22 | Data += Nfixed; | |
23 | Size -= Nfixed; | |
24 | ||
25 | Item2 item2 = fmt_fuzzer::assignFromBuf<Item2>(Data); | |
26 | Data += Nfixed; | |
27 | Size -= Nfixed; | |
28 | ||
29 | auto fmtstring = fmt::string_view(fmt_fuzzer::as_chars(Data), Size); | |
30 | ||
31 | #if FMT_FUZZ_FORMAT_TO_STRING | |
32 | std::string message = fmt::format(fmtstring, item1, item2); | |
33 | #else | |
34 | fmt::memory_buffer message; | |
35 | fmt::format_to(message, fmtstring, item1, item2); | |
36 | #endif | |
37 | } | |
38 | ||
39 | // for dynamic dispatching to an explicit instantiation | |
40 | template <typename Callback> void invoke(int index, Callback callback) { | |
41 | switch (index) { | |
42 | case 0: | |
43 | callback(bool{}); | |
44 | break; | |
45 | case 1: | |
46 | callback(char{}); | |
47 | break; | |
48 | case 2: | |
49 | using sc = signed char; | |
50 | callback(sc{}); | |
51 | break; | |
52 | case 3: | |
53 | using uc = unsigned char; | |
54 | callback(uc{}); | |
55 | break; | |
56 | case 4: | |
57 | callback(short{}); | |
58 | break; | |
59 | case 5: | |
60 | using us = unsigned short; | |
61 | callback(us{}); | |
62 | break; | |
63 | case 6: | |
64 | callback(int{}); | |
65 | break; | |
66 | case 7: | |
67 | callback(unsigned{}); | |
68 | break; | |
69 | case 8: | |
70 | callback(long{}); | |
71 | break; | |
72 | case 9: | |
73 | using ul = unsigned long; | |
74 | callback(ul{}); | |
75 | break; | |
76 | case 10: | |
77 | callback(float{}); | |
78 | break; | |
79 | case 11: | |
80 | callback(double{}); | |
81 | break; | |
82 | case 12: | |
83 | using LD = long double; | |
84 | callback(LD{}); | |
85 | break; | |
86 | case 13: | |
87 | using ptr = void*; | |
88 | callback(ptr{}); | |
89 | break; | |
90 | } | |
91 | } | |
92 | ||
93 | extern "C" int LLVMFuzzerTestOneInput(const uint8_t* Data, size_t Size) { | |
94 | if (Size <= 3) { | |
95 | return 0; | |
96 | } | |
97 | ||
98 | // switch types depending on the first byte of the input | |
99 | const auto first = Data[0] & 0x0F; | |
100 | const auto second = (Data[0] & 0xF0) >> 4; | |
101 | Data++; | |
102 | Size--; | |
103 | ||
104 | auto outer = [=](auto param1) { | |
105 | auto inner = [=](auto param2) { | |
106 | invoke_fmt<decltype(param1), decltype(param2)>(Data, Size); | |
107 | }; | |
108 | invoke(second, inner); | |
109 | }; | |
110 | ||
111 | try { | |
112 | invoke(first, outer); | |
113 | } catch (std::exception& /*e*/) { | |
114 | } | |
115 | return 0; | |
116 | } |