Coverage Report

Created: 2026-06-15 06:25

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/wasm_interp_fuzzer.cc
Line
Count
Source
1
// Copyright 2026 Google LLC
2
//
3
// Licensed under the Apache License, Version 2.0 (the "License");
4
// you may not use this file except in compliance with the License.
5
// You may obtain a copy of the License at
6
//
7
//      http://www.apache.org/licenses/LICENSE-2.0
8
//
9
// Unless required by applicable law or agreed to in writing, software
10
// distributed under the License is distributed on an "AS IS" BASIS,
11
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
// See the License for the specific language governing permissions and
13
// limitations under the License.
14
15
#include <cstddef>
16
#include <cstdint>
17
#include <vector>
18
19
#include "wabt/interp/binary-reader-interp.h"
20
#include "wabt/binary-reader.h"
21
#include "wabt/interp/interp.h"
22
#include "wabt/interp/interp-util.h"
23
24
extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
25
  wabt::Errors errors;
26
  wabt::Features features;
27
  // Enable all features for more coverage.
28
#define WABT_FEATURE(variable, flag, default_, help) features.enable_##variable();
29
#include "wabt/feature.def"
30
#undef WABT_FEATURE
31
32
  wabt::interp::Store store;
33
  store.setFeatures(features);
34
35
  wabt::interp::ModuleDesc module_desc;
36
  wabt::ReadBinaryOptions options(features, nullptr, true, true, true);
37
  if (wabt::Succeeded(wabt::interp::ReadBinaryInterp("<fuzzer>", data, size, options, &errors, &module_desc))) {
38
    // Check for excessive memory allocation to avoid OOM.
39
    for (auto&& mem : module_desc.memories) {
40
      if (mem.type.limits.initial > 1024) {
41
        return 0;
42
      }
43
    }
44
45
    wabt::interp::Module::Ptr module = wabt::interp::Module::New(store, module_desc);
46
    wabt::interp::RefVec imports;
47
    
48
    // Bind dummy imports
49
    for (auto&& import : module->desc().imports) {
50
      if (import.type.type->kind == wabt::interp::ExternKind::Func) {
51
        auto func_type = *wabt::cast<wabt::interp::FuncType>(import.type.type.get());
52
        auto host_func = wabt::interp::HostFunc::New(
53
            store, func_type,
54
            [](wabt::interp::Thread& thread, const wabt::interp::Values& params,
55
0
               wabt::interp::Values& results, wabt::interp::Trap::Ptr* trap) -> wabt::Result {
56
0
              return wabt::Result::Ok;
57
0
            });
58
        imports.push_back(host_func.ref());
59
      } else {
60
        imports.push_back(wabt::interp::Ref::Null);
61
      }
62
    }
63
64
    wabt::interp::Instance::Ptr instance;
65
    wabt::interp::Trap::Ptr trap;
66
    instance = wabt::interp::Instance::Instantiate(store, module.ref(), imports, &trap);
67
    if (instance) {
68
      // Run all exported functions that have no parameters.
69
      // This is a simple way to exercise the interpreter without complex argument generation.
70
      for (auto&& export_ : module->desc().exports) {
71
        if (export_.type.type->kind == wabt::ExternalKind::Func) {
72
          auto* func_type = wabt::cast<wabt::interp::FuncType>(export_.type.type.get());
73
          if (func_type->params.empty()) {
74
            auto func = store.UnsafeGet<wabt::interp::Func>(instance->funcs()[export_.index]);
75
            wabt::interp::Values params;
76
            wabt::interp::Values results;
77
            wabt::interp::Trap::Ptr call_trap;
78
            func->Call(store, params, results, &call_trap);
79
          }
80
        }
81
      }
82
    }
83
  }
84
85
  return 0;
86
}