]> git.proxmox.com Git - ceph.git/blob - ceph/src/fmt/test/fuzzing/named_arg.cpp
update source to Ceph Pacific 16.2.2
[ceph.git] / ceph / src / fmt / test / fuzzing / named_arg.cpp
1 // Copyright (c) 2019, Paul Dreik
2 // License: see LICENSE.rst in the fmt root directory
3
4 #include <fmt/chrono.h>
5 #include <fmt/core.h>
6 #include <cstdint>
7 #include <stdexcept>
8 #include <type_traits>
9 #include <vector>
10 #include "fuzzer_common.h"
11
12 template <typename Item1>
13 void invoke_fmt(const uint8_t* Data, size_t Size, unsigned int argsize) {
14 constexpr auto N1 = sizeof(Item1);
15 static_assert(N1 <= fmt_fuzzer::Nfixed, "Nfixed too small");
16 if (Size <= fmt_fuzzer::Nfixed) {
17 return;
18 }
19 const Item1 item1 = fmt_fuzzer::assignFromBuf<Item1>(Data);
20
21 Data += fmt_fuzzer::Nfixed;
22 Size -= fmt_fuzzer::Nfixed;
23
24 // how many chars should be used for the argument name?
25 if (argsize <= 0 || argsize >= Size) {
26 return;
27 }
28
29 // allocating buffers separately is slower, but increases chances
30 // of detecting memory errors
31 #if FMT_FUZZ_SEPARATE_ALLOCATION
32 std::vector<char> argnamebuffer(argsize + 1);
33 std::memcpy(argnamebuffer.data(), Data, argsize);
34 auto argname = argnamebuffer.data();
35 #else
36 auto argname = fmt_fuzzer::as_chars(Data);
37 #endif
38 Data += argsize;
39 Size -= argsize;
40
41 #if FMT_FUZZ_SEPARATE_ALLOCATION
42 // allocates as tight as possible, making it easier to catch buffer overruns.
43 std::vector<char> fmtstringbuffer(Size);
44 std::memcpy(fmtstringbuffer.data(), Data, Size);
45 auto fmtstring = fmt::string_view(fmtstringbuffer.data(), Size);
46 #else
47 auto fmtstring = fmt::string_view(fmt_fuzzer::as_chars(Data), Size);
48 #endif
49
50 #if FMT_FUZZ_FORMAT_TO_STRING
51 std::string message = fmt::format(fmtstring, fmt::arg(argname, item1));
52 #else
53 fmt::memory_buffer outbuf;
54 fmt::format_to(outbuf, fmtstring, fmt::arg(argname, item1));
55 #endif
56 }
57
58 // for dynamic dispatching to an explicit instantiation
59 template <typename Callback> void invoke(int index, Callback callback) {
60 switch (index) {
61 case 0:
62 callback(bool{});
63 break;
64 case 1:
65 callback(char{});
66 break;
67 case 2:
68 using sc = signed char;
69 callback(sc{});
70 break;
71 case 3:
72 using uc = unsigned char;
73 callback(uc{});
74 break;
75 case 4:
76 callback(short{});
77 break;
78 case 5:
79 using us = unsigned short;
80 callback(us{});
81 break;
82 case 6:
83 callback(int{});
84 break;
85 case 7:
86 callback(unsigned{});
87 break;
88 case 8:
89 callback(long{});
90 break;
91 case 9:
92 using ul = unsigned long;
93 callback(ul{});
94 break;
95 case 10:
96 callback(float{});
97 break;
98 case 11:
99 callback(double{});
100 break;
101 case 12:
102 using LD = long double;
103 callback(LD{});
104 break;
105 }
106 }
107
108 extern "C" int LLVMFuzzerTestOneInput(const uint8_t* Data, size_t Size) {
109 if (Size <= 3) {
110 return 0;
111 }
112
113 // switch types depending on the first byte of the input
114 const auto first = Data[0] & 0x0F;
115 const unsigned int second = (Data[0] & 0xF0) >> 4;
116 Data++;
117 Size--;
118
119 auto outerfcn = [=](auto param1) {
120 invoke_fmt<decltype(param1)>(Data, Size, second);
121 };
122
123 try {
124 invoke(first, outerfcn);
125 } catch (std::exception& /*e*/) {
126 }
127 return 0;
128 }