1 // Copyright (c) 2019, Paul Dreik
2 // For the license information refer to format.h.
3
4 #include <cstdint>
5 #include <fmt/chrono.h>
6
7 #include "fuzzer-common.h"
8
9 template <typename Period, typename Rep>
invoke_inner(fmt::string_view format_str,Rep rep)10 void invoke_inner(fmt::string_view format_str, Rep rep) {
11 auto value = std::chrono::duration<Rep, Period>(rep);
12 try {
13 #if FMT_FUZZ_FORMAT_TO_STRING
14 std::string message = fmt::format(format_str, value);
15 #else
16 fmt::memory_buffer buf;
17 fmt::format_to(buf, format_str, value);
18 #endif
19 } catch (std::exception&) {
20 }
21 }
22
23 // Rep is a duration's representation type.
24 template <typename Rep>
invoke_outer(const uint8_t * data,size_t size,int period)25 void invoke_outer(const uint8_t* data, size_t size, int period) {
26 // Always use a fixed location of the data.
27 static_assert(sizeof(Rep) <= fixed_size, "fixed size is too small");
28 if (size <= fixed_size + 1) return;
29
30 const Rep rep = assign_from_buf<Rep>(data);
31 data += fixed_size;
32 size -= fixed_size;
33
34 // data is already allocated separately in libFuzzer so reading past the end
35 // will most likely be detected anyway.
36 const auto format_str = fmt::string_view(as_chars(data), size);
37
38 // yocto, zepto, zetta and yotta are not handled.
39 switch (period) {
40 case 1:
41 invoke_inner<std::atto>(format_str, rep);
42 break;
43 case 2:
44 invoke_inner<std::femto>(format_str, rep);
45 break;
46 case 3:
47 invoke_inner<std::pico>(format_str, rep);
48 break;
49 case 4:
50 invoke_inner<std::nano>(format_str, rep);
51 break;
52 case 5:
53 invoke_inner<std::micro>(format_str, rep);
54 break;
55 case 6:
56 invoke_inner<std::milli>(format_str, rep);
57 break;
58 case 7:
59 invoke_inner<std::centi>(format_str, rep);
60 break;
61 case 8:
62 invoke_inner<std::deci>(format_str, rep);
63 break;
64 case 9:
65 invoke_inner<std::deca>(format_str, rep);
66 break;
67 case 10:
68 invoke_inner<std::kilo>(format_str, rep);
69 break;
70 case 11:
71 invoke_inner<std::mega>(format_str, rep);
72 break;
73 case 12:
74 invoke_inner<std::giga>(format_str, rep);
75 break;
76 case 13:
77 invoke_inner<std::tera>(format_str, rep);
78 break;
79 case 14:
80 invoke_inner<std::peta>(format_str, rep);
81 break;
82 case 15:
83 invoke_inner<std::exa>(format_str, rep);
84 break;
85 }
86 }
87
LLVMFuzzerTestOneInput(const uint8_t * data,size_t size)88 extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
89 if (size <= 4) return 0;
90
91 const auto representation = data[0];
92 const auto period = data[1];
93 data += 2;
94 size -= 2;
95
96 switch (representation) {
97 case 1:
98 invoke_outer<char>(data, size, period);
99 break;
100 case 2:
101 invoke_outer<signed char>(data, size, period);
102 break;
103 case 3:
104 invoke_outer<unsigned char>(data, size, period);
105 break;
106 case 4:
107 invoke_outer<short>(data, size, period);
108 break;
109 case 5:
110 invoke_outer<unsigned short>(data, size, period);
111 break;
112 case 6:
113 invoke_outer<int>(data, size, period);
114 break;
115 case 7:
116 invoke_outer<unsigned int>(data, size, period);
117 break;
118 case 8:
119 invoke_outer<long>(data, size, period);
120 break;
121 case 9:
122 invoke_outer<unsigned long>(data, size, period);
123 break;
124 case 10:
125 invoke_outer<float>(data, size, period);
126 break;
127 case 11:
128 invoke_outer<double>(data, size, period);
129 break;
130 case 12:
131 invoke_outer<long double>(data, size, period);
132 break;
133 }
134 return 0;
135 }
136