/src/WasmEdge/lib/driver/fuzzPO.cpp
Line | Count | Source |
1 | | // SPDX-License-Identifier: Apache-2.0 |
2 | | // SPDX-FileCopyrightText: Copyright The WasmEdge Authors |
3 | | |
4 | | #ifdef WASMEDGE_BUILD_FUZZING |
5 | | #include "driver/fuzzPO.h" |
6 | | #include "common/spdlog.h" |
7 | | #include "common/version.h" |
8 | | #include "po/argument_parser.h" |
9 | | |
10 | | #include <algorithm> |
11 | | #include <array> |
12 | | #include <cstdio> |
13 | | #include <type_traits> |
14 | | #include <utility> |
15 | | #include <vector> |
16 | | |
17 | | namespace { |
18 | | template <class Key, class Value, class Hash, class BinaryPredicate> |
19 | | class SkipTable { |
20 | | private: |
21 | | using UnsignedKey = std::make_unsigned_t<Key>; |
22 | | std::array<Value, |
23 | | static_cast<std::size_t>(std::numeric_limits<UnsignedKey>::max()) + |
24 | | 1u> |
25 | | Table; |
26 | | |
27 | | public: |
28 | 1 | SkipTable(std::size_t, Value Default, Hash, BinaryPredicate) { |
29 | 1 | std::fill_n(Table.begin(), Table.size(), Default); |
30 | 1 | } |
31 | | |
32 | 3 | void insert(const Key &K, Value V) { Table[static_cast<UnsignedKey>(K)] = V; } |
33 | | |
34 | 22.3M | const Value &at(const Key &K) const { |
35 | 22.3M | return Table[static_cast<UnsignedKey>(K)]; |
36 | 22.3M | } |
37 | | }; |
38 | | |
39 | | template <class RandomIt1, |
40 | | class Hash = |
41 | | std::hash<typename std::iterator_traits<RandomIt1>::value_type>, |
42 | | class BinaryPredicate = std::equal_to<>> |
43 | | class BoyerMooreHorspoolSearcher { |
44 | | private: |
45 | | using Key = typename std::iterator_traits<RandomIt1>::value_type; |
46 | | using Value = typename std::iterator_traits<RandomIt1>::difference_type; |
47 | | static_assert(std::is_integral_v<Key> && sizeof(Key) == 1 && |
48 | | std::is_same_v<Hash, std::hash<Key>> && |
49 | | std::is_same_v<BinaryPredicate, std::equal_to<>>); |
50 | | using SkipTableType = SkipTable<Key, Value, Hash, BinaryPredicate>; |
51 | | |
52 | | public: |
53 | | BoyerMooreHorspoolSearcher(RandomIt1 First, RandomIt1 Last, Hash HF = Hash(), |
54 | | BinaryPredicate Pred = BinaryPredicate()) |
55 | 1 | : Pattern(First), PatternLength(std::distance(First, Last)), Pred(Pred), |
56 | 1 | Table(PatternLength, PatternLength, HF, Pred) { |
57 | 1 | if (First != Last) { |
58 | 1 | --Last; |
59 | 4 | for (Value I = 0; First != Last; ++First, ++I) { |
60 | 3 | Table.insert(*First, PatternLength - 1 - I); |
61 | 3 | } |
62 | 1 | } |
63 | 1 | } |
64 | | |
65 | | template <class RandomIt2> |
66 | | std::pair<RandomIt2, RandomIt2> operator()(RandomIt2 First, |
67 | 1.39M | RandomIt2 Last) const { |
68 | 1.39M | static_assert( |
69 | 1.39M | std::is_same_v< |
70 | 1.39M | std::remove_cv_t<std::remove_reference_t< |
71 | 1.39M | typename std::iterator_traits<RandomIt1>::value_type>>, |
72 | 1.39M | std::remove_cv_t<std::remove_reference_t< |
73 | 1.39M | typename std::iterator_traits<RandomIt2>::value_type>>>, |
74 | 1.39M | "Corpus and Pattern iterators must point to the same type"); |
75 | 1.39M | if (First == Last) { |
76 | | // empty corpus |
77 | 0 | return {Last, Last}; |
78 | 0 | } |
79 | 1.39M | if (PatternLength == 0) { |
80 | | // empty pattern |
81 | 0 | return {First, First}; |
82 | 0 | } |
83 | | // the pattern is larger than the corpus |
84 | 1.39M | if (PatternLength > std::distance(First, Last)) { |
85 | 580 | return {Last, Last}; |
86 | 580 | } |
87 | | |
88 | 1.39M | RandomIt2 Curr = First; |
89 | 1.39M | const RandomIt2 End = Last - PatternLength; |
90 | 23.7M | while (Curr <= End) { |
91 | 23.7M | Value J = PatternLength; |
92 | 28.2M | while (Pred(Pattern[J - 1], Curr[J - 1])) { |
93 | 5.83M | --J; |
94 | 5.83M | if (J == 0) { |
95 | | // found |
96 | 1.38M | return {Curr, Curr + PatternLength}; |
97 | 1.38M | } |
98 | 5.83M | } |
99 | 22.3M | const auto K = Curr[PatternLength - 1]; |
100 | 22.3M | const auto D = Table.at(K); |
101 | 22.3M | Curr += D; |
102 | 22.3M | } |
103 | 1.00k | return {Last, Last}; |
104 | 1.39M | } |
105 | | |
106 | | private: |
107 | | RandomIt1 Pattern; |
108 | | Value PatternLength; |
109 | | BinaryPredicate Pred; |
110 | | SkipTableType Table; |
111 | | }; |
112 | | } // namespace |
113 | | |
114 | | namespace WasmEdge { |
115 | | namespace Driver { |
116 | | |
117 | 1.61k | int FuzzPO(const uint8_t *Data, size_t Size) noexcept { |
118 | 1.61k | using namespace std::literals; |
119 | | |
120 | 1.61k | std::ios::sync_with_stdio(false); |
121 | 1.61k | spdlog::set_level(spdlog::level::info); |
122 | | |
123 | 1.61k | PO::Option<std::string> SoName(PO::Description("Wasm or so file"sv), |
124 | 1.61k | PO::MetaVar("WASM_OR_SO"sv)); |
125 | 1.61k | PO::List<std::string> Args(PO::Description("Execution arguments"sv), |
126 | 1.61k | PO::MetaVar("ARG"sv)); |
127 | | |
128 | 1.61k | PO::Option<PO::Toggle> Reactor(PO::Description( |
129 | 1.61k | "Enable reactor mode. Reactor mode calls `_initialize` if exported.")); |
130 | | |
131 | 1.61k | PO::List<std::string> Dir( |
132 | 1.61k | PO::Description( |
133 | 1.61k | "Binding directories into WASI virtual filesystem. Each directories " |
134 | 1.61k | "can specified as --dir `guest_path:host_path`, where `guest_path` " |
135 | 1.61k | "specifies the path that will correspond to `host_path` for calls " |
136 | 1.61k | "like `fopen` in the guest."sv), |
137 | 1.61k | PO::MetaVar("PREOPEN_DIRS"sv)); |
138 | | |
139 | 1.61k | PO::List<std::string> Env( |
140 | 1.61k | PO::Description( |
141 | 1.61k | "Environ variables. Each variable can be specified as --env `NAME=VALUE`."sv), |
142 | 1.61k | PO::MetaVar("ENVS"sv)); |
143 | | |
144 | 1.61k | PO::Option<PO::Toggle> PropWASM1( |
145 | 1.61k | PO::Description("Set as WASM 1.0 standard."sv)); |
146 | 1.61k | PO::Option<PO::Toggle> PropWASM2( |
147 | 1.61k | PO::Description("Set as WASM 2.0 standard."sv)); |
148 | 1.61k | PO::Option<PO::Toggle> PropWASM3( |
149 | 1.61k | PO::Description("Set as WASM 3.0 standard (default)."sv)); |
150 | 1.61k | PO::Option<PO::Toggle> PropMutGlobals( |
151 | 1.61k | PO::Description("Disable Import/Export of mutable globals proposal"sv)); |
152 | 1.61k | PO::Option<PO::Toggle> PropNonTrapF2IConvs(PO::Description( |
153 | 1.61k | "Disable Non-trapping float-to-int conversions proposal"sv)); |
154 | 1.61k | PO::Option<PO::Toggle> PropSignExtendOps( |
155 | 1.61k | PO::Description("Disable Sign-extension operators proposal"sv)); |
156 | 1.61k | PO::Option<PO::Toggle> PropMultiValue( |
157 | 1.61k | PO::Description("Disable Multi-value proposal"sv)); |
158 | 1.61k | PO::Option<PO::Toggle> PropBulkMemOps( |
159 | 1.61k | PO::Description("Disable Bulk memory operations proposal"sv)); |
160 | 1.61k | PO::Option<PO::Toggle> PropRefTypes( |
161 | 1.61k | PO::Description("Disable Reference types proposal"sv)); |
162 | 1.61k | PO::Option<PO::Toggle> PropSIMD(PO::Description("Disable SIMD proposal"sv)); |
163 | 1.61k | PO::Option<PO::Toggle> PropTailCall( |
164 | 1.61k | PO::Description("Disable Tail-call proposal"sv)); |
165 | 1.61k | PO::Option<PO::Toggle> PropExtendConst( |
166 | 1.61k | PO::Description("Disable Extended-const proposal"sv)); |
167 | 1.61k | PO::Option<PO::Toggle> PropFunctionReference( |
168 | 1.61k | PO::Description("Disable Function Reference proposal"sv)); |
169 | 1.61k | PO::Option<PO::Toggle> PropGC(PO::Description("Disable GC proposal"sv)); |
170 | 1.61k | PO::Option<PO::Toggle> PropMultiMem( |
171 | 1.61k | PO::Description("Disable Multiple memories proposal"sv)); |
172 | 1.61k | PO::Option<PO::Toggle> PropRelaxedSIMD( |
173 | 1.61k | PO::Description("Disable Relaxed SIMD proposal"sv)); |
174 | 1.61k | PO::Option<PO::Toggle> PropExceptionHandling( |
175 | 1.61k | PO::Description("Disable Exception handling proposal"sv)); |
176 | | // TODO: MEMORY64 - enable the option. |
177 | | // PO::Option<PO::Toggle> PropMemory64( |
178 | | // PO::Description("Disable Memory64 proposal"sv)); |
179 | 1.61k | PO::Option<PO::Toggle> PropThreads( |
180 | 1.61k | PO::Description("Enable Threads proposal"sv)); |
181 | 1.61k | PO::Option<PO::Toggle> PropComponent(PO::Description( |
182 | 1.61k | "Enable Component Model proposal, this is experimental"sv)); |
183 | 1.61k | PO::Option<PO::Toggle> PropAll(PO::Description("Enable all features"sv)); |
184 | | |
185 | 1.61k | PO::Option<PO::Toggle> ConfEnableInstructionCounting(PO::Description( |
186 | 1.61k | "Enable generating code for counting Wasm instructions executed."sv)); |
187 | 1.61k | PO::Option<PO::Toggle> ConfEnableGasMeasuring(PO::Description( |
188 | 1.61k | "Enable generating code for counting gas burned during execution."sv)); |
189 | 1.61k | PO::Option<PO::Toggle> ConfEnableTimeMeasuring(PO::Description( |
190 | 1.61k | "Enable generating code for counting time during execution."sv)); |
191 | 1.61k | PO::Option<PO::Toggle> ConfEnableAllStatistics(PO::Description( |
192 | 1.61k | "Enable generating code for all statistics options include instruction counting, gas measuring, and execution time"sv)); |
193 | | |
194 | 1.61k | PO::Option<uint64_t> TimeLim( |
195 | 1.61k | PO::Description( |
196 | 1.61k | "Limitation of maximum time(in milliseconds) for execution, default value is 0 for no limitations"sv), |
197 | 1.61k | PO::MetaVar("TIMEOUT"sv), PO::DefaultValue<uint64_t>(0)); |
198 | | |
199 | 1.61k | PO::List<int> GasLim( |
200 | 1.61k | PO::Description( |
201 | 1.61k | "Limitation of execution gas. Upper bound can be specified as --gas-limit `GAS_LIMIT`."sv), |
202 | 1.61k | PO::MetaVar("GAS_LIMIT"sv)); |
203 | | |
204 | 1.61k | PO::List<int> MemLim( |
205 | 1.61k | PO::Description( |
206 | 1.61k | "Limitation of pages(as size of 64 KiB) in every memory instance. Upper bound can be specified as --memory-page-limit `PAGE_COUNT`."sv), |
207 | 1.61k | PO::MetaVar("PAGE_COUNT"sv)); |
208 | | |
209 | 1.61k | PO::List<std::string> ForbiddenPlugins( |
210 | 1.61k | PO::Description("List of plugins to ignore."sv), PO::MetaVar("NAMES"sv)); |
211 | | |
212 | 1.61k | auto Parser = PO::ArgumentParser(); |
213 | 1.61k | Parser.add_option(SoName) |
214 | 1.61k | .add_option(Args) |
215 | 1.61k | .add_option("reactor"sv, Reactor) |
216 | 1.61k | .add_option("dir"sv, Dir) |
217 | 1.61k | .add_option("env"sv, Env) |
218 | 1.61k | .add_option("wasm-1"sv, PropWASM1) |
219 | 1.61k | .add_option("wasm-2"sv, PropWASM2) |
220 | 1.61k | .add_option("wasm-3"sv, PropWASM3) |
221 | 1.61k | .add_option("disable-import-export-mut-globals"sv, PropMutGlobals) |
222 | 1.61k | .add_option("disable-non-trap-float-to-int"sv, PropNonTrapF2IConvs) |
223 | 1.61k | .add_option("disable-sign-extension-operators"sv, PropSignExtendOps) |
224 | 1.61k | .add_option("disable-multi-value"sv, PropMultiValue) |
225 | 1.61k | .add_option("disable-bulk-memory"sv, PropBulkMemOps) |
226 | 1.61k | .add_option("disable-reference-types"sv, PropRefTypes) |
227 | 1.61k | .add_option("disable-simd"sv, PropSIMD) |
228 | 1.61k | .add_option("disable-tail-call"sv, PropTailCall) |
229 | 1.61k | .add_option("disable-extended-const"sv, PropExtendConst) |
230 | 1.61k | .add_option("disable-function-reference"sv, PropFunctionReference) |
231 | 1.61k | .add_option("disable-gc"sv, PropGC) |
232 | 1.61k | .add_option("disable-multi-memory"sv, PropMultiMem) |
233 | 1.61k | .add_option("disable-relaxed-simd"sv, PropRelaxedSIMD) |
234 | 1.61k | .add_option("disable-exception-handling"sv, PropExceptionHandling) |
235 | | // TODO: MEMORY64 - enable the option. |
236 | | // .add_option("disable-memory64"sv, PropMemory64) |
237 | 1.61k | .add_option("enable-threads"sv, PropThreads) |
238 | 1.61k | .add_option("enable-component"sv, PropComponent) |
239 | 1.61k | .add_option("enable-all"sv, PropAll) |
240 | 1.61k | .add_option("time-limit"sv, TimeLim) |
241 | 1.61k | .add_option("gas-limit"sv, GasLim) |
242 | 1.61k | .add_option("memory-page-limit"sv, MemLim) |
243 | 1.61k | .add_option("forbidden-plugin"sv, ForbiddenPlugins); |
244 | | |
245 | 1.61k | static constexpr const std::array<char, 4> Separator = {'\xde', '\xad', |
246 | 1.61k | '\xbe', '\xef'}; |
247 | 1.61k | static const BoyerMooreHorspoolSearcher Searcher(Separator.begin(), |
248 | 1.61k | Separator.end()); |
249 | 1.61k | Span<const char> RawArgs(reinterpret_cast<const char *>(Data), Size); |
250 | 1.61k | std::vector<std::string> ArgvStr; |
251 | 1.61k | std::vector<const char *> Argv; |
252 | 1.39M | while (!RawArgs.empty()) { |
253 | 1.39M | const auto It = std::search(RawArgs.begin(), RawArgs.end(), Searcher); |
254 | 1.39M | ArgvStr.emplace_back(RawArgs.begin(), It); |
255 | 1.39M | RawArgs = RawArgs.subspan(std::min<size_t>( |
256 | 1.39M | std::distance(RawArgs.begin(), It) + 4, RawArgs.size())); |
257 | 1.39M | } |
258 | 1.39M | for (const auto &Arg : ArgvStr) { |
259 | 1.39M | Argv.push_back(Arg.c_str()); |
260 | 1.39M | } |
261 | | |
262 | 1.61k | std::unique_ptr<std::FILE, decltype(&std::fclose)> Out{ |
263 | 1.61k | std::fopen("/dev/null", "w"), std::fclose}; |
264 | 1.61k | if (!Parser.parse(Out.get(), Argv.size(), Argv.data())) { |
265 | 930 | return EXIT_FAILURE; |
266 | 930 | } |
267 | 683 | if (Parser.isVersion()) { |
268 | 200 | fmt::print(Out.get(), "{} version {}\n"sv, Argv.empty() ? "" : Argv[0], |
269 | 200 | kVersionString); |
270 | 200 | return EXIT_SUCCESS; |
271 | 200 | } |
272 | | |
273 | 483 | return EXIT_SUCCESS; |
274 | 683 | } |
275 | | |
276 | | } // namespace Driver |
277 | | } // namespace WasmEdge |
278 | | #endif |