Line data Source code
1 : // Copyright 2017 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 : #include <stdlib.h>
8 :
9 : #include <algorithm>
10 :
11 : #include "include/v8.h"
12 : #include "src/isolate.h"
13 : #include "src/objects-inl.h"
14 : #include "src/objects.h"
15 : #include "src/ostreams.h"
16 : #include "src/wasm/wasm-interpreter.h"
17 : #include "src/wasm/wasm-module-builder.h"
18 : #include "src/wasm/wasm-module.h"
19 : #include "test/common/wasm/test-signatures.h"
20 : #include "test/common/wasm/wasm-module-runner.h"
21 : #include "test/fuzzer/fuzzer-support.h"
22 : #include "test/fuzzer/wasm-fuzzer-common.h"
23 :
24 : typedef uint8_t byte;
25 :
26 : namespace v8 {
27 : namespace internal {
28 : namespace wasm {
29 : namespace fuzzer {
30 :
31 : namespace {
32 :
33 : class DataRange {
34 : const uint8_t* data_;
35 : size_t size_;
36 :
37 : public:
38 1 : DataRange(const uint8_t* data, size_t size) : data_(data), size_(size) {}
39 :
40 : size_t size() const { return size_; }
41 :
42 : std::pair<DataRange, DataRange> split(uint32_t index) const {
43 : return std::make_pair(DataRange(data_, index),
44 0 : DataRange(data_ + index, size() - index));
45 : }
46 :
47 0 : std::pair<DataRange, DataRange> split() {
48 0 : uint16_t index = get<uint16_t>();
49 0 : if (size() > 0) {
50 0 : index = index % size();
51 : } else {
52 : index = 0;
53 : }
54 : return split(index);
55 : }
56 :
57 : template <typename T>
58 1 : T get() {
59 1 : if (size() == 0) {
60 : return T();
61 : } else {
62 : // We want to support the case where we have less than sizeof(T) bytes
63 : // remaining in the slice. For example, if we emit an i32 constant, it's
64 : // okay if we don't have a full four bytes available, we'll just use what
65 : // we have. We aren't concerned about endianness because we are generating
66 : // arbitrary expressions.
67 0 : const size_t num_bytes = std::min(sizeof(T), size());
68 0 : T result = T();
69 0 : memcpy(&result, data_, num_bytes);
70 0 : data_ += num_bytes;
71 0 : size_ -= num_bytes;
72 0 : return result;
73 : }
74 : }
75 : };
76 :
77 : class WasmGenerator {
78 : template <WasmOpcode Op, ValueType... Args>
79 : std::function<void(DataRange)> op() {
80 0 : return [this](DataRange data) {
81 0 : Generate<Args...>(data);
82 0 : builder_->Emit(Op);
83 0 : };
84 : }
85 :
86 : template <ValueType T>
87 : std::function<void(DataRange)> block() {
88 0 : return [this](DataRange data) {
89 0 : blocks_.push_back(T);
90 0 : builder_->EmitWithU8(
91 0 : kExprBlock, static_cast<uint8_t>(WasmOpcodes::ValueTypeCodeFor(T)));
92 0 : Generate<T>(data);
93 0 : builder_->Emit(kExprEnd);
94 0 : blocks_.pop_back();
95 0 : };
96 : }
97 :
98 : template <ValueType T>
99 : std::function<void(DataRange)> block_br() {
100 0 : return [this](DataRange data) {
101 0 : blocks_.push_back(T);
102 0 : builder_->EmitWithU8(
103 0 : kExprBlock, static_cast<uint8_t>(WasmOpcodes::ValueTypeCodeFor(T)));
104 :
105 0 : const uint32_t target_block = data.get<uint32_t>() % blocks_.size();
106 0 : const ValueType break_type = blocks_[target_block];
107 :
108 0 : Generate(break_type, data);
109 0 : builder_->EmitWithI32V(kExprBr, target_block);
110 0 : builder_->Emit(kExprEnd);
111 0 : blocks_.pop_back();
112 0 : };
113 : }
114 :
115 : public:
116 1 : explicit WasmGenerator(WasmFunctionBuilder* fn) : builder_(fn) {}
117 :
118 : void Generate(ValueType type, DataRange data);
119 :
120 : template <ValueType T>
121 : void Generate(DataRange data);
122 :
123 : template <ValueType T1, ValueType T2, ValueType... Ts>
124 0 : void Generate(DataRange data) {
125 : const auto parts = data.split();
126 0 : Generate<T1>(parts.first);
127 0 : Generate<T2, Ts...>(parts.second);
128 0 : }
129 :
130 : private:
131 : WasmFunctionBuilder* builder_;
132 : std::vector<ValueType> blocks_;
133 : };
134 :
135 : template <>
136 1 : void WasmGenerator::Generate<kWasmI32>(DataRange data) {
137 1 : if (data.size() <= sizeof(uint32_t)) {
138 1 : builder_->EmitI32Const(data.get<uint32_t>());
139 : } else {
140 : const std::function<void(DataRange)> alternates[] = {
141 : op<kExprI32Eqz, kWasmI32>(), //
142 : op<kExprI32Eq, kWasmI32, kWasmI32>(),
143 : op<kExprI32Ne, kWasmI32, kWasmI32>(),
144 : op<kExprI32LtS, kWasmI32, kWasmI32>(),
145 : op<kExprI32LtU, kWasmI32, kWasmI32>(),
146 : op<kExprI32GeS, kWasmI32, kWasmI32>(),
147 : op<kExprI32GeU, kWasmI32, kWasmI32>(),
148 :
149 : op<kExprI64Eqz, kWasmI64>(), //
150 : op<kExprI64Eq, kWasmI64, kWasmI64>(),
151 : op<kExprI64Ne, kWasmI64, kWasmI64>(),
152 : op<kExprI64LtS, kWasmI64, kWasmI64>(),
153 : op<kExprI64LtU, kWasmI64, kWasmI64>(),
154 : op<kExprI64GeS, kWasmI64, kWasmI64>(),
155 : op<kExprI64GeU, kWasmI64, kWasmI64>(),
156 :
157 : op<kExprF32Eq, kWasmF32, kWasmF32>(),
158 : op<kExprF32Ne, kWasmF32, kWasmF32>(),
159 : op<kExprF32Lt, kWasmF32, kWasmF32>(),
160 : op<kExprF32Ge, kWasmF32, kWasmF32>(),
161 :
162 : op<kExprF64Eq, kWasmF64, kWasmF64>(),
163 : op<kExprF64Ne, kWasmF64, kWasmF64>(),
164 : op<kExprF64Lt, kWasmF64, kWasmF64>(),
165 : op<kExprF64Ge, kWasmF64, kWasmF64>(),
166 :
167 : op<kExprI32Add, kWasmI32, kWasmI32>(),
168 : op<kExprI32Sub, kWasmI32, kWasmI32>(),
169 : op<kExprI32Mul, kWasmI32, kWasmI32>(),
170 :
171 : op<kExprI32DivS, kWasmI32, kWasmI32>(),
172 : op<kExprI32DivU, kWasmI32, kWasmI32>(),
173 : op<kExprI32RemS, kWasmI32, kWasmI32>(),
174 : op<kExprI32RemU, kWasmI32, kWasmI32>(),
175 :
176 : op<kExprI32And, kWasmI32, kWasmI32>(),
177 : op<kExprI32Ior, kWasmI32, kWasmI32>(),
178 : op<kExprI32Xor, kWasmI32, kWasmI32>(),
179 : op<kExprI32Shl, kWasmI32, kWasmI32>(),
180 : op<kExprI32ShrU, kWasmI32, kWasmI32>(),
181 : op<kExprI32ShrS, kWasmI32, kWasmI32>(),
182 : op<kExprI32Ror, kWasmI32, kWasmI32>(),
183 : op<kExprI32Rol, kWasmI32, kWasmI32>(),
184 :
185 : op<kExprI32Clz, kWasmI32>(), //
186 : op<kExprI32Ctz, kWasmI32>(), //
187 : op<kExprI32Popcnt, kWasmI32>(),
188 :
189 : op<kExprI32ConvertI64, kWasmI64>(), //
190 : op<kExprI32SConvertF32, kWasmF32>(),
191 : op<kExprI32UConvertF32, kWasmF32>(),
192 : op<kExprI32SConvertF64, kWasmF64>(),
193 : op<kExprI32UConvertF64, kWasmF64>(),
194 : op<kExprI32ReinterpretF32, kWasmF32>(),
195 :
196 : block<kWasmI32>(),
197 : block_br<kWasmI32>()};
198 :
199 : static_assert(arraysize(alternates) < std::numeric_limits<uint8_t>::max(),
200 : "Too many alternates. Replace with a bigger type if needed.");
201 0 : const auto which = data.get<uint8_t>();
202 :
203 0 : alternates[which % arraysize(alternates)](data);
204 : }
205 1 : }
206 :
207 : template <>
208 0 : void WasmGenerator::Generate<kWasmI64>(DataRange data) {
209 0 : if (data.size() <= sizeof(uint64_t)) {
210 0 : builder_->EmitI64Const(data.get<int64_t>());
211 : } else {
212 : const std::function<void(DataRange)> alternates[] = {
213 : op<kExprI64Add, kWasmI64, kWasmI64>(),
214 : op<kExprI64Sub, kWasmI64, kWasmI64>(),
215 : op<kExprI64Mul, kWasmI64, kWasmI64>(),
216 :
217 : op<kExprI64DivS, kWasmI64, kWasmI64>(),
218 : op<kExprI64DivU, kWasmI64, kWasmI64>(),
219 : op<kExprI64RemS, kWasmI64, kWasmI64>(),
220 : op<kExprI64RemU, kWasmI64, kWasmI64>(),
221 :
222 : op<kExprI64And, kWasmI64, kWasmI64>(),
223 : op<kExprI64Ior, kWasmI64, kWasmI64>(),
224 : op<kExprI64Xor, kWasmI64, kWasmI64>(),
225 : op<kExprI64Shl, kWasmI64, kWasmI64>(),
226 : op<kExprI64ShrU, kWasmI64, kWasmI64>(),
227 : op<kExprI64ShrS, kWasmI64, kWasmI64>(),
228 : op<kExprI64Ror, kWasmI64, kWasmI64>(),
229 : op<kExprI64Rol, kWasmI64, kWasmI64>(),
230 :
231 : op<kExprI64Clz, kWasmI64>(),
232 : op<kExprI64Ctz, kWasmI64>(),
233 : op<kExprI64Popcnt, kWasmI64>(),
234 :
235 : block<kWasmI64>(),
236 : block_br<kWasmI64>()};
237 :
238 : static_assert(arraysize(alternates) < std::numeric_limits<uint8_t>::max(),
239 : "Too many alternates. Replace with a bigger type if needed.");
240 0 : const auto which = data.get<uint8_t>();
241 :
242 0 : alternates[which % arraysize(alternates)](data);
243 : }
244 0 : }
245 :
246 : template <>
247 0 : void WasmGenerator::Generate<kWasmF32>(DataRange data) {
248 0 : if (data.size() <= sizeof(float)) {
249 0 : builder_->EmitF32Const(data.get<float>());
250 : } else {
251 : const std::function<void(DataRange)> alternates[] = {
252 : op<kExprF32Add, kWasmF32, kWasmF32>(),
253 : op<kExprF32Sub, kWasmF32, kWasmF32>(),
254 : op<kExprF32Mul, kWasmF32, kWasmF32>(),
255 :
256 : block<kWasmF32>(), block_br<kWasmF32>()};
257 :
258 : static_assert(arraysize(alternates) < std::numeric_limits<uint8_t>::max(),
259 : "Too many alternates. Replace with a bigger type if needed.");
260 0 : const auto which = data.get<uint8_t>();
261 :
262 0 : alternates[which % arraysize(alternates)](data);
263 : }
264 0 : }
265 :
266 : template <>
267 0 : void WasmGenerator::Generate<kWasmF64>(DataRange data) {
268 0 : if (data.size() <= sizeof(double)) {
269 0 : builder_->EmitF64Const(data.get<double>());
270 : } else {
271 : const std::function<void(DataRange)> alternates[] = {
272 : op<kExprF64Add, kWasmF64, kWasmF64>(),
273 : op<kExprF64Sub, kWasmF64, kWasmF64>(),
274 : op<kExprF64Mul, kWasmF64, kWasmF64>(),
275 :
276 : block<kWasmF64>(), block_br<kWasmF64>()};
277 :
278 : static_assert(arraysize(alternates) < std::numeric_limits<uint8_t>::max(),
279 : "Too many alternates. Replace with a bigger type if needed.");
280 0 : const auto which = data.get<uint8_t>();
281 :
282 0 : alternates[which % arraysize(alternates)](data);
283 : }
284 0 : }
285 :
286 0 : void WasmGenerator::Generate(ValueType type, DataRange data) {
287 0 : switch (type) {
288 : case kWasmI32:
289 0 : return Generate<kWasmI32>(data);
290 : case kWasmI64:
291 0 : return Generate<kWasmI64>(data);
292 : case kWasmF32:
293 0 : return Generate<kWasmF32>(data);
294 : case kWasmF64:
295 0 : return Generate<kWasmF64>(data);
296 : default:
297 0 : UNREACHABLE();
298 : }
299 : }
300 : } // namespace
301 :
302 1 : class WasmCompileFuzzer : public WasmExecutionFuzzer {
303 1 : bool GenerateModule(
304 : Isolate* isolate, Zone* zone, const uint8_t* data, size_t size,
305 : ZoneBuffer& buffer, int32_t& num_args,
306 : std::unique_ptr<WasmValue[]>& interpreter_args,
307 : std::unique_ptr<Handle<Object>[]>& compiler_args) override {
308 1 : TestSignatures sigs;
309 :
310 1 : WasmModuleBuilder builder(zone);
311 :
312 1 : WasmFunctionBuilder* f = builder.AddFunction(sigs.i_iii());
313 :
314 : WasmGenerator gen(f);
315 2 : gen.Generate<kWasmI32>(DataRange(data, static_cast<uint32_t>(size)));
316 :
317 1 : uint8_t end_opcode = kExprEnd;
318 1 : f->EmitCode(&end_opcode, 1);
319 1 : builder.AddExport(CStrVector("main"), f);
320 :
321 1 : builder.SetMaxMemorySize(32);
322 1 : builder.WriteTo(buffer);
323 :
324 1 : num_args = 3;
325 : interpreter_args.reset(
326 1 : new WasmValue[3]{WasmValue(1), WasmValue(2), WasmValue(3)});
327 :
328 : compiler_args.reset(new Handle<Object>[3]{
329 : handle(Smi::FromInt(1), isolate), handle(Smi::FromInt(1), isolate),
330 1 : handle(Smi::FromInt(1), isolate)});
331 1 : return true;
332 : }
333 : };
334 :
335 1 : extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
336 2 : return WasmCompileFuzzer().FuzzWasmModule(data, size);
337 : }
338 :
339 : } // namespace fuzzer
340 : } // namespace wasm
341 : } // namespace internal
342 : } // namespace v8
|