Line data Source code
1 : // Copyright 2016 the V8 project authors. All rights reserved.
2 : // Use of this source code is governed by a BSD-style license that can be
3 : // found in the LICENSE file.
4 :
5 : #include <stddef.h>
6 : #include <stdint.h>
7 :
8 : #include "include/v8.h"
9 : #include "src/isolate.h"
10 : #include "src/objects-inl.h"
11 : #include "src/objects.h"
12 : #include "src/utils.h"
13 : #include "src/wasm/wasm-interpreter.h"
14 : #include "src/wasm/wasm-module-builder.h"
15 : #include "src/wasm/wasm-module.h"
16 : #include "test/common/wasm/test-signatures.h"
17 : #include "test/common/wasm/wasm-module-runner.h"
18 : #include "test/fuzzer/fuzzer-support.h"
19 : #include "test/fuzzer/wasm-fuzzer-common.h"
20 :
21 : namespace v8 {
22 : namespace internal {
23 : namespace wasm {
24 : namespace fuzzer {
25 :
26 : static constexpr uint32_t kMaxNumFunctions = 3;
27 : static constexpr uint32_t kMaxNumParams = 3;
28 :
29 0 : class WasmCallFuzzer : public WasmExecutionFuzzer {
30 : template <typename V>
31 : static inline V read_value(const uint8_t** data, size_t* size, bool* ok) {
32 : // The status flag {ok} checks that the decoding up until now was okay, and
33 : // that a value of type V can be read without problems.
34 3 : *ok &= (*size > sizeof(V));
35 3 : if (!(*ok)) return 0;
36 0 : V result = ReadLittleEndianValue<V>(*data);
37 0 : *data += sizeof(V);
38 0 : *size -= sizeof(V);
39 : return result;
40 : }
41 :
42 1 : static void add_argument(Isolate* isolate, ValueType type,
43 : WasmValue* interpreter_args,
44 : Handle<Object>* compiler_args, int* argc,
45 : const uint8_t** data, size_t* size, bool* ok) {
46 2 : if (!(*ok)) return;
47 0 : switch (type) {
48 : case kWasmF32: {
49 : float value = read_value<float>(data, size, ok);
50 0 : interpreter_args[*argc] = WasmValue(value);
51 : compiler_args[*argc] =
52 0 : isolate->factory()->NewNumber(static_cast<double>(value));
53 0 : break;
54 : }
55 : case kWasmF64: {
56 : double value = read_value<double>(data, size, ok);
57 0 : interpreter_args[*argc] = WasmValue(value);
58 0 : compiler_args[*argc] = isolate->factory()->NewNumber(value);
59 0 : break;
60 : }
61 : case kWasmI32: {
62 : int32_t value = read_value<int32_t>(data, size, ok);
63 0 : interpreter_args[*argc] = WasmValue(value);
64 : compiler_args[*argc] =
65 0 : isolate->factory()->NewNumber(static_cast<double>(value));
66 0 : break;
67 : }
68 : default:
69 0 : UNREACHABLE();
70 : }
71 0 : (*argc)++;
72 : }
73 :
74 1 : bool GenerateModule(
75 : Isolate* isolate, Zone* zone, const uint8_t* data, size_t size,
76 : ZoneBuffer& buffer, int32_t& num_args,
77 : std::unique_ptr<WasmValue[]>& interpreter_args,
78 : std::unique_ptr<Handle<Object>[]>& compiler_args) override {
79 1 : bool ok = true;
80 : uint8_t num_functions =
81 1 : (read_value<uint8_t>(&data, &size, &ok) % kMaxNumFunctions) + 1;
82 :
83 1 : ValueType types[] = {kWasmF32, kWasmF64, kWasmI32, kWasmI64};
84 :
85 4 : interpreter_args.reset(new WasmValue[3]);
86 4 : compiler_args.reset(new Handle<Object>[3]);
87 :
88 1 : WasmModuleBuilder builder(zone);
89 2 : for (int fun = 0; fun < num_functions; fun++) {
90 : size_t num_params = static_cast<size_t>(
91 1 : (read_value<uint8_t>(&data, &size, &ok) % kMaxNumParams) + 1);
92 : FunctionSig::Builder sig_builder(zone, 1, num_params);
93 : sig_builder.AddReturn(kWasmI32);
94 2 : for (size_t param = 0; param < num_params; param++) {
95 : // The main function cannot handle int64 parameters.
96 2 : ValueType param_type = types[(read_value<uint8_t>(&data, &size, &ok) %
97 2 : (arraysize(types) - (fun == 0 ? 1 : 0)))];
98 : sig_builder.AddParam(param_type);
99 1 : if (fun == 0) {
100 : add_argument(isolate, param_type, interpreter_args.get(),
101 1 : compiler_args.get(), &num_args, &data, &size, &ok);
102 : }
103 : }
104 1 : WasmFunctionBuilder* f = builder.AddFunction(sig_builder.Build());
105 1 : uint32_t code_size = static_cast<uint32_t>(size / num_functions);
106 1 : f->EmitCode(data, code_size);
107 1 : uint8_t end_opcode = kExprEnd;
108 1 : f->EmitCode(&end_opcode, 1);
109 1 : data += code_size;
110 1 : size -= code_size;
111 1 : if (fun == 0) {
112 1 : builder.AddExport(CStrVector("main"), f);
113 : }
114 : }
115 :
116 1 : builder.SetMaxMemorySize(32);
117 1 : builder.WriteTo(buffer);
118 :
119 1 : if (!ok) {
120 : // The input data was too short.
121 : return 0;
122 : }
123 0 : return true;
124 : }
125 : };
126 :
127 1 : extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
128 2 : return WasmCallFuzzer().FuzzWasmModule(data, size);
129 : }
130 :
131 : } // namespace fuzzer
132 : } // namespace wasm
133 : } // namespace internal
134 : } // namespace v8
|