summaryrefslogtreecommitdiff
path: root/deps/v8/test/fuzzer/wasm-call.cc
blob: 5c855023811480483a6cc803b4ff3b6d72881077 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
// Copyright 2016 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include <stddef.h>
#include <stdint.h>

#include "include/v8.h"
#include "src/isolate.h"
#include "src/objects-inl.h"
#include "src/objects.h"
#include "src/utils.h"
#include "src/wasm/wasm-interpreter.h"
#include "src/wasm/wasm-module-builder.h"
#include "src/wasm/wasm-module.h"
#include "test/common/wasm/test-signatures.h"
#include "test/common/wasm/wasm-module-runner.h"
#include "test/fuzzer/fuzzer-support.h"
#include "test/fuzzer/wasm-fuzzer-common.h"

namespace v8 {
namespace internal {
namespace wasm {
namespace fuzzer {

static constexpr uint32_t kMaxNumFunctions = 3;
static constexpr uint32_t kMaxNumParams = 3;

class WasmCallFuzzer : public WasmExecutionFuzzer {
  template <typename V>
  static inline V read_value(const uint8_t** data, size_t* size, bool* ok) {
    // The status flag {ok} checks that the decoding up until now was okay, and
    // that a value of type V can be read without problems.
    *ok &= (*size > sizeof(V));
    if (!(*ok)) return 0;
    V result = ReadLittleEndianValue<V>(*data);
    *data += sizeof(V);
    *size -= sizeof(V);
    return result;
  }

  static void add_argument(Isolate* isolate, ValueType type,
                           WasmValue* interpreter_args,
                           Handle<Object>* compiler_args, int* argc,
                           const uint8_t** data, size_t* size, bool* ok) {
    if (!(*ok)) return;
    switch (type) {
      case kWasmF32: {
        float value = read_value<float>(data, size, ok);
        interpreter_args[*argc] = WasmValue(value);
        compiler_args[*argc] =
            isolate->factory()->NewNumber(static_cast<double>(value));
        break;
      }
      case kWasmF64: {
        double value = read_value<double>(data, size, ok);
        interpreter_args[*argc] = WasmValue(value);
        compiler_args[*argc] = isolate->factory()->NewNumber(value);
        break;
      }
      case kWasmI32: {
        int32_t value = read_value<int32_t>(data, size, ok);
        interpreter_args[*argc] = WasmValue(value);
        compiler_args[*argc] =
            isolate->factory()->NewNumber(static_cast<double>(value));
        break;
      }
      default:
        UNREACHABLE();
    }
    (*argc)++;
  }

  bool GenerateModule(
      Isolate* isolate, Zone* zone, const uint8_t* data, size_t size,
      ZoneBuffer& buffer, int32_t& num_args,
      std::unique_ptr<WasmValue[]>& interpreter_args,
      std::unique_ptr<Handle<Object>[]>& compiler_args) override {
    bool ok = true;
    uint8_t num_functions =
        (read_value<uint8_t>(&data, &size, &ok) % kMaxNumFunctions) + 1;

    ValueType types[] = {kWasmF32, kWasmF64, kWasmI32, kWasmI64};

    interpreter_args.reset(new WasmValue[3]);
    compiler_args.reset(new Handle<Object>[3]);

    WasmModuleBuilder builder(zone);
    for (int fun = 0; fun < num_functions; fun++) {
      size_t num_params = static_cast<size_t>(
          (read_value<uint8_t>(&data, &size, &ok) % kMaxNumParams) + 1);
      FunctionSig::Builder sig_builder(zone, 1, num_params);
      sig_builder.AddReturn(kWasmI32);
      for (size_t param = 0; param < num_params; param++) {
        // The main function cannot handle int64 parameters.
        ValueType param_type = types[(read_value<uint8_t>(&data, &size, &ok) %
                                      (arraysize(types) - (fun == 0 ? 1 : 0)))];
        sig_builder.AddParam(param_type);
        if (fun == 0) {
          add_argument(isolate, param_type, interpreter_args.get(),
                       compiler_args.get(), &num_args, &data, &size, &ok);
        }
      }
      WasmFunctionBuilder* f = builder.AddFunction(sig_builder.Build());
      uint32_t code_size = static_cast<uint32_t>(size / num_functions);
      f->EmitCode(data, code_size);
      uint8_t end_opcode = kExprEnd;
      f->EmitCode(&end_opcode, 1);
      data += code_size;
      size -= code_size;
      if (fun == 0) {
        builder.AddExport(CStrVector("main"), f);
      }
    }

    builder.SetMaxMemorySize(32);
    builder.WriteTo(buffer);

    if (!ok) {
      // The input data was too short.
      return 0;
    }
    return true;
  }
};

extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
  return WasmCallFuzzer().FuzzWasmModule(data, size);
}

}  // namespace fuzzer
}  // namespace wasm
}  // namespace internal
}  // namespace v8