Coverage Report

Created: 2026-06-30 06:10

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/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