Coverage Report

Created: 2026-06-13 07:57

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
0
extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
25
0
  wabt::Errors errors;
26
0
  wabt::Features features;
27
  // Enable all features for more coverage.
28
0
#define WABT_FEATURE(variable, flag, default_, help) features.enable_##variable();
29
0
#include "wabt/feature.def"
30
0
#undef WABT_FEATURE
31
32
0
  wabt::interp::Store store;
33
0
  store.setFeatures(features);
34
35
0
  wabt::interp::ModuleDesc module_desc;
36
0
  wabt::ReadBinaryOptions options(features, nullptr, true, true, true);
37
0
  if (wabt::Succeeded(wabt::interp::ReadBinaryInterp("<fuzzer>", data, size, options, &errors, &module_desc))) {
38
    // Check for excessive memory allocation to avoid OOM.
39
0
    for (auto&& mem : module_desc.memories) {
40
0
      if (mem.type.limits.initial > 1024) {
41
0
        return 0;
42
0
      }
43
0
    }
44
45
0
    wabt::interp::Module::Ptr module = wabt::interp::Module::New(store, module_desc);
46
0
    wabt::interp::RefVec imports;
47
    
48
    // Bind dummy imports
49
0
    for (auto&& import : module->desc().imports) {
50
0
      if (import.type.type->kind == wabt::interp::ExternKind::Func) {
51
0
        auto func_type = *wabt::cast<wabt::interp::FuncType>(import.type.type.get());
52
0
        auto host_func = wabt::interp::HostFunc::New(
53
0
            store, func_type,
54
0
            [](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
0
        imports.push_back(host_func.ref());
59
0
      } else {
60
0
        imports.push_back(wabt::interp::Ref::Null);
61
0
      }
62
0
    }
63
64
0
    wabt::interp::Instance::Ptr instance;
65
0
    wabt::interp::Trap::Ptr trap;
66
0
    instance = wabt::interp::Instance::Instantiate(store, module.ref(), imports, &trap);
67
0
    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
0
      for (auto&& export_ : module->desc().exports) {
71
0
        if (export_.type.type->kind == wabt::ExternalKind::Func) {
72
0
          auto* func_type = wabt::cast<wabt::interp::FuncType>(export_.type.type.get());
73
0
          if (func_type->params.empty()) {
74
0
            auto func = store.UnsafeGet<wabt::interp::Func>(instance->funcs()[export_.index]);
75
0
            wabt::interp::Values params;
76
0
            wabt::interp::Values results;
77
0
            wabt::interp::Trap::Ptr call_trap;
78
0
            func->Call(store, params, results, &call_trap);
79
0
          }
80
0
        }
81
0
      }
82
0
    }
83
0
  }
84
85
0
  return 0;
86
0
}