1 // Copyright (c) 2019, Paul Dreik
2 // License: see LICENSE.rst in the fmt root directory
3 #include <fmt/format.h>
4 #include <cstdint>
5 #include <stdexcept>
6 #include <type_traits>
7
8 #include "fuzzer_common.h"
9
10 constexpr auto Nfixed = fmt_fuzzer::Nfixed;
11
12 template <typename Item1, typename Item2>
invoke_fmt(const uint8_t * Data,std::size_t Size)13 void invoke_fmt(const uint8_t* Data, std::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 const Item1 item1 = fmt_fuzzer::assignFromBuf<Item1>(Data);
22 Data += Nfixed;
23 Size -= Nfixed;
24
25 const 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
invoke(int index,Callback callback)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 }
87 }
88
LLVMFuzzerTestOneInput(const uint8_t * Data,std::size_t Size)89 extern "C" int LLVMFuzzerTestOneInput(const uint8_t* Data, std::size_t Size) {
90 if (Size <= 3) {
91 return 0;
92 }
93
94 // switch types depending on the first byte of the input
95 const auto first = Data[0] & 0x0F;
96 const auto second = (Data[0] & 0xF0) >> 4;
97 Data++;
98 Size--;
99
100 auto outer = [=](auto param1) {
101 auto inner = [=](auto param2) {
102 invoke_fmt<decltype(param1), decltype(param2)>(Data, Size);
103 };
104 invoke(second, inner);
105 };
106
107 try {
108 invoke(first, outer);
109 } catch (std::exception& /*e*/) {
110 }
111 return 0;
112 }
113