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 : constexpr int kMaxFunctions = 4;
34 : constexpr int kMaxGlobals = 64;
35 :
36 : class DataRange {
37 : Vector<const uint8_t> data_;
38 :
39 : public:
40 2 : explicit DataRange(Vector<const uint8_t> data) : data_(data) {}
41 :
42 : // Don't accidentally pass DataRange by value. This will reuse bytes and might
43 : // lead to OOM because the end might not be reached.
44 : // Define move constructor and move assignment, disallow copy constructor and
45 : // copy assignment (below).
46 : DataRange(DataRange&& other) V8_NOEXCEPT : DataRange(other.data_) {
47 1 : other.data_ = {};
48 : }
49 : DataRange& operator=(DataRange&& other) V8_NOEXCEPT {
50 : data_ = other.data_;
51 : other.data_ = {};
52 : return *this;
53 : }
54 :
55 1 : size_t size() const { return data_.size(); }
56 :
57 0 : DataRange split() {
58 0 : uint16_t num_bytes = get<uint16_t>() % std::max(size_t{1}, data_.size());
59 0 : DataRange split(data_.SubVector(0, num_bytes));
60 : data_ += num_bytes;
61 0 : return split;
62 : }
63 :
64 : template <typename T, size_t max_bytes = sizeof(T)>
65 4 : T get() {
66 : STATIC_ASSERT(max_bytes <= sizeof(T));
67 : // We want to support the case where we have less than sizeof(T) bytes
68 : // remaining in the slice. For example, if we emit an i32 constant, it's
69 : // okay if we don't have a full four bytes available, we'll just use what
70 : // we have. We aren't concerned about endianness because we are generating
71 : // arbitrary expressions.
72 12 : const size_t num_bytes = std::min(max_bytes, data_.size());
73 4 : T result = T();
74 : memcpy(&result, data_.start(), num_bytes);
75 : data_ += num_bytes;
76 4 : return result;
77 : }
78 :
79 : DISALLOW_COPY_AND_ASSIGN(DataRange);
80 : };
81 :
82 0 : ValueType GetValueType(DataRange& data) {
83 0 : switch (data.get<uint8_t>() % 4) {
84 : case 0:
85 : return kWasmI32;
86 : case 1:
87 0 : return kWasmI64;
88 : case 2:
89 0 : return kWasmF32;
90 : case 3:
91 0 : return kWasmF64;
92 : }
93 0 : UNREACHABLE();
94 : }
95 :
96 2 : class WasmGenerator {
97 : template <WasmOpcode Op, ValueType... Args>
98 0 : void op(DataRange& data) {
99 0 : Generate<Args...>(data);
100 0 : builder_->Emit(Op);
101 0 : }
102 :
103 : class BlockScope {
104 : public:
105 0 : BlockScope(WasmGenerator* gen, WasmOpcode block_type, ValueType result_type,
106 : ValueType br_type)
107 0 : : gen_(gen) {
108 0 : gen->blocks_.push_back(br_type);
109 : gen->builder_->EmitWithU8(block_type,
110 0 : ValueTypes::ValueTypeCodeFor(result_type));
111 0 : }
112 :
113 0 : ~BlockScope() {
114 0 : gen_->builder_->Emit(kExprEnd);
115 0 : gen_->blocks_.pop_back();
116 0 : }
117 :
118 : private:
119 : WasmGenerator* const gen_;
120 : };
121 :
122 : template <ValueType T>
123 0 : void block(DataRange& data) {
124 0 : BlockScope block_scope(this, kExprBlock, T, T);
125 0 : Generate<T>(data);
126 0 : }
127 :
128 : template <ValueType T>
129 0 : void loop(DataRange& data) {
130 : // When breaking to a loop header, don't provide any input value (hence
131 : // kWasmStmt).
132 0 : BlockScope block_scope(this, kExprLoop, T, kWasmStmt);
133 0 : Generate<T>(data);
134 0 : }
135 :
136 : enum IfType { kIf, kIfElse };
137 :
138 : template <ValueType T, IfType type>
139 0 : void if_(DataRange& data) {
140 : static_assert(T == kWasmStmt || type == kIfElse,
141 : "if without else cannot produce a value");
142 0 : Generate<kWasmI32>(data);
143 0 : BlockScope block_scope(this, kExprIf, T, T);
144 0 : Generate<T>(data);
145 : if (type == kIfElse) {
146 0 : builder_->Emit(kExprElse);
147 0 : Generate<T>(data);
148 0 : }
149 0 : }
150 :
151 0 : void br(DataRange& data) {
152 : // There is always at least the block representing the function body.
153 : DCHECK(!blocks_.empty());
154 0 : const uint32_t target_block = data.get<uint32_t>() % blocks_.size();
155 0 : const ValueType break_type = blocks_[target_block];
156 :
157 0 : Generate(break_type, data);
158 : builder_->EmitWithI32V(
159 0 : kExprBr, static_cast<uint32_t>(blocks_.size()) - 1 - target_block);
160 0 : }
161 :
162 : template <ValueType wanted_type>
163 0 : void br_if(DataRange& data) {
164 : // There is always at least the block representing the function body.
165 : DCHECK(!blocks_.empty());
166 0 : const uint32_t target_block = data.get<uint32_t>() % blocks_.size();
167 0 : const ValueType break_type = blocks_[target_block];
168 :
169 0 : Generate(break_type, data);
170 0 : Generate(kWasmI32, data);
171 0 : builder_->EmitWithI32V(
172 0 : kExprBrIf, static_cast<uint32_t>(blocks_.size()) - 1 - target_block);
173 0 : ConvertOrGenerate(break_type, wanted_type, data);
174 0 : }
175 :
176 : // TODO(eholk): make this function constexpr once gcc supports it
177 : static uint8_t max_alignment(WasmOpcode memop) {
178 : switch (memop) {
179 : case kExprI64LoadMem:
180 : case kExprF64LoadMem:
181 : case kExprI64StoreMem:
182 : case kExprF64StoreMem:
183 : return 3;
184 : case kExprI32LoadMem:
185 : case kExprI64LoadMem32S:
186 : case kExprI64LoadMem32U:
187 : case kExprF32LoadMem:
188 : case kExprI32StoreMem:
189 : case kExprI64StoreMem32:
190 : case kExprF32StoreMem:
191 : return 2;
192 : case kExprI32LoadMem16S:
193 : case kExprI32LoadMem16U:
194 : case kExprI64LoadMem16S:
195 : case kExprI64LoadMem16U:
196 : case kExprI32StoreMem16:
197 : case kExprI64StoreMem16:
198 : return 1;
199 : case kExprI32LoadMem8S:
200 : case kExprI32LoadMem8U:
201 : case kExprI64LoadMem8S:
202 : case kExprI64LoadMem8U:
203 : case kExprI32StoreMem8:
204 : case kExprI64StoreMem8:
205 : return 0;
206 : default:
207 : return 0;
208 : }
209 : }
210 :
211 : template <WasmOpcode memory_op, ValueType... arg_types>
212 0 : void memop(DataRange& data) {
213 0 : const uint8_t align = data.get<uint8_t>() % (max_alignment(memory_op) + 1);
214 0 : const uint32_t offset = data.get<uint32_t>();
215 :
216 : // Generate the index and the arguments, if any.
217 0 : Generate<kWasmI32, arg_types...>(data);
218 :
219 0 : builder_->Emit(memory_op);
220 0 : builder_->EmitU32V(align);
221 0 : builder_->EmitU32V(offset);
222 0 : }
223 :
224 0 : void drop(DataRange& data) {
225 0 : Generate(GetValueType(data), data);
226 0 : builder_->Emit(kExprDrop);
227 0 : }
228 :
229 : template <ValueType wanted_type>
230 0 : void call(DataRange& data) {
231 0 : call(data, wanted_type);
232 0 : }
233 :
234 0 : void Convert(ValueType src, ValueType dst) {
235 0 : auto idx = [](ValueType t) -> int {
236 0 : switch (t) {
237 : case kWasmI32:
238 : return 0;
239 : case kWasmI64:
240 : return 1;
241 : case kWasmF32:
242 : return 2;
243 : case kWasmF64:
244 : return 3;
245 : default:
246 0 : UNREACHABLE();
247 : }
248 : };
249 : static constexpr WasmOpcode kConvertOpcodes[] = {
250 : // {i32, i64, f32, f64} -> i32
251 : kExprNop, kExprI32ConvertI64, kExprI32SConvertF32, kExprI32SConvertF64,
252 : // {i32, i64, f32, f64} -> i64
253 : kExprI64SConvertI32, kExprNop, kExprI64SConvertF32, kExprI64SConvertF64,
254 : // {i32, i64, f32, f64} -> f32
255 : kExprF32SConvertI32, kExprF32SConvertI64, kExprNop, kExprF32ConvertF64,
256 : // {i32, i64, f32, f64} -> f64
257 : kExprF64SConvertI32, kExprF64SConvertI64, kExprF64ConvertF32, kExprNop};
258 0 : int arr_idx = idx(dst) << 2 | idx(src);
259 0 : builder_->Emit(kConvertOpcodes[arr_idx]);
260 0 : }
261 :
262 0 : void ConvertOrGenerate(ValueType src, ValueType dst, DataRange& data) {
263 0 : if (src == dst) return;
264 0 : if (src == kWasmStmt && dst != kWasmStmt) {
265 0 : Generate(dst, data);
266 0 : } else if (dst == kWasmStmt && src != kWasmStmt) {
267 0 : builder_->Emit(kExprDrop);
268 : } else {
269 0 : Convert(src, dst);
270 : }
271 : }
272 :
273 0 : void call(DataRange& data, ValueType wanted_type) {
274 0 : int func_index = data.get<uint8_t>() % functions_.size();
275 0 : FunctionSig* sig = functions_[func_index];
276 : // Generate arguments.
277 0 : for (size_t i = 0; i < sig->parameter_count(); ++i) {
278 0 : Generate(sig->GetParam(i), data);
279 : }
280 : // Emit call.
281 0 : builder_->EmitWithU32V(kExprCallFunction, func_index);
282 : // Convert the return value to the wanted type.
283 : ValueType return_type =
284 0 : sig->return_count() == 0 ? kWasmStmt : sig->GetReturn(0);
285 0 : if (return_type == kWasmStmt && wanted_type != kWasmStmt) {
286 : // The call did not generate a value. Thus just generate it here.
287 0 : Generate(wanted_type, data);
288 0 : } else if (return_type != kWasmStmt && wanted_type == kWasmStmt) {
289 : // The call did generate a value, but we did not want one.
290 0 : builder_->Emit(kExprDrop);
291 0 : } else if (return_type != wanted_type) {
292 : // If the returned type does not match the wanted type, convert it.
293 0 : Convert(return_type, wanted_type);
294 : }
295 0 : }
296 :
297 : struct Var {
298 : uint32_t index;
299 : ValueType type = kWasmStmt;
300 : Var() = default;
301 : Var(uint32_t index, ValueType type) : index(index), type(type) {}
302 : bool is_valid() const { return type != kWasmStmt; }
303 : };
304 :
305 0 : Var GetRandomLocal(DataRange& data) {
306 : uint32_t num_params =
307 0 : static_cast<uint32_t>(builder_->signature()->parameter_count());
308 0 : uint32_t num_locals = static_cast<uint32_t>(locals_.size());
309 0 : if (num_params + num_locals == 0) return {};
310 0 : uint32_t index = data.get<uint8_t>() % (num_params + num_locals);
311 0 : ValueType type = index < num_params ? builder_->signature()->GetParam(index)
312 0 : : locals_[index - num_params];
313 0 : return {index, type};
314 : }
315 :
316 : template <ValueType wanted_type>
317 0 : void local_op(DataRange& data, WasmOpcode opcode) {
318 0 : Var local = GetRandomLocal(data);
319 : // If there are no locals and no parameters, just generate any value (if a
320 : // value is needed), or do nothing.
321 0 : if (!local.is_valid()) {
322 0 : if (wanted_type == kWasmStmt) return;
323 0 : return Generate<wanted_type>(data);
324 : }
325 :
326 0 : if (opcode != kExprGetLocal) Generate(local.type, data);
327 0 : builder_->EmitWithU32V(opcode, local.index);
328 0 : if (wanted_type != kWasmStmt && local.type != wanted_type) {
329 0 : Convert(local.type, wanted_type);
330 : }
331 : }
332 :
333 : template <ValueType wanted_type>
334 0 : void get_local(DataRange& data) {
335 : static_assert(wanted_type != kWasmStmt, "illegal type");
336 0 : local_op<wanted_type>(data, kExprGetLocal);
337 0 : }
338 :
339 0 : void set_local(DataRange& data) { local_op<kWasmStmt>(data, kExprSetLocal); }
340 :
341 : template <ValueType wanted_type>
342 0 : void tee_local(DataRange& data) {
343 0 : local_op<wanted_type>(data, kExprTeeLocal);
344 0 : }
345 :
346 : template <size_t num_bytes>
347 0 : void i32_const(DataRange& data) {
348 0 : builder_->EmitI32Const(data.get<int32_t, num_bytes>());
349 0 : }
350 :
351 : template <size_t num_bytes>
352 0 : void i64_const(DataRange& data) {
353 0 : builder_->EmitI64Const(data.get<int64_t, num_bytes>());
354 0 : }
355 :
356 0 : Var GetRandomGlobal(DataRange& data, bool ensure_mutable) {
357 : uint32_t index;
358 0 : if (ensure_mutable) {
359 0 : if (mutable_globals_.empty()) return {};
360 0 : index = mutable_globals_[data.get<uint8_t>() % mutable_globals_.size()];
361 : } else {
362 0 : if (globals_.empty()) return {};
363 0 : index = data.get<uint8_t>() % globals_.size();
364 : }
365 0 : ValueType type = globals_[index];
366 0 : return {index, type};
367 : }
368 :
369 : template <ValueType wanted_type>
370 0 : void global_op(DataRange& data) {
371 : constexpr bool is_set = wanted_type == kWasmStmt;
372 0 : Var global = GetRandomGlobal(data, is_set);
373 : // If there are no globals, just generate any value (if a value is needed),
374 : // or do nothing.
375 0 : if (!global.is_valid()) {
376 0 : if (wanted_type == kWasmStmt) return;
377 0 : return Generate<wanted_type>(data);
378 : }
379 :
380 0 : if (is_set) Generate(global.type, data);
381 0 : builder_->EmitWithU32V(is_set ? kExprSetGlobal : kExprGetGlobal,
382 0 : global.index);
383 0 : if (!is_set && global.type != wanted_type) {
384 0 : Convert(global.type, wanted_type);
385 : }
386 : }
387 :
388 : template <ValueType wanted_type>
389 0 : void get_global(DataRange& data) {
390 : static_assert(wanted_type != kWasmStmt, "illegal type");
391 0 : global_op<wanted_type>(data);
392 0 : }
393 :
394 0 : void set_global(DataRange& data) { global_op<kWasmStmt>(data); }
395 :
396 : template <ValueType... Types>
397 0 : void sequence(DataRange& data) {
398 0 : Generate<Types...>(data);
399 0 : }
400 :
401 0 : void current_memory(DataRange& data) {
402 0 : builder_->EmitWithU8(kExprMemorySize, 0);
403 0 : }
404 :
405 : void grow_memory(DataRange& data);
406 :
407 : using generate_fn = void (WasmGenerator::*const)(DataRange&);
408 :
409 : template <size_t N>
410 0 : void GenerateOneOf(generate_fn (&alternates)[N], DataRange& data) {
411 : static_assert(N < std::numeric_limits<uint8_t>::max(),
412 : "Too many alternates. Replace with a bigger type if needed.");
413 0 : const auto which = data.get<uint8_t>();
414 :
415 0 : generate_fn alternate = alternates[which % N];
416 0 : (this->*alternate)(data);
417 0 : }
418 :
419 : struct GeneratorRecursionScope {
420 : explicit GeneratorRecursionScope(WasmGenerator* gen) : gen(gen) {
421 1 : ++gen->recursion_depth;
422 : DCHECK_LE(gen->recursion_depth, kMaxRecursionDepth);
423 : }
424 : ~GeneratorRecursionScope() {
425 : DCHECK_GT(gen->recursion_depth, 0);
426 1 : --gen->recursion_depth;
427 : }
428 : WasmGenerator* gen;
429 : };
430 :
431 : public:
432 2 : WasmGenerator(WasmFunctionBuilder* fn,
433 : const std::vector<FunctionSig*>& functions,
434 : const std::vector<ValueType>& globals,
435 : const std::vector<uint8_t>& mutable_globals, DataRange& data)
436 : : builder_(fn),
437 : functions_(functions),
438 : globals_(globals),
439 3 : mutable_globals_(mutable_globals) {
440 2 : FunctionSig* sig = fn->signature();
441 : DCHECK_GE(1, sig->return_count());
442 3 : blocks_.push_back(sig->return_count() == 0 ? kWasmStmt : sig->GetReturn(0));
443 :
444 : constexpr uint32_t kMaxLocals = 32;
445 1 : locals_.resize(data.get<uint8_t>() % kMaxLocals);
446 2 : for (ValueType& local : locals_) {
447 0 : local = GetValueType(data);
448 0 : fn->AddLocal(local);
449 : }
450 1 : }
451 :
452 : void Generate(ValueType type, DataRange& data);
453 :
454 : template <ValueType T>
455 : void Generate(DataRange& data);
456 :
457 : template <ValueType T1, ValueType T2, ValueType... Ts>
458 0 : void Generate(DataRange& data) {
459 : // TODO(clemensh): Implement a more even split.
460 0 : auto first_data = data.split();
461 0 : Generate<T1>(first_data);
462 0 : Generate<T2, Ts...>(data);
463 0 : }
464 :
465 : private:
466 : WasmFunctionBuilder* builder_;
467 : std::vector<ValueType> blocks_;
468 : const std::vector<FunctionSig*>& functions_;
469 : std::vector<ValueType> locals_;
470 : std::vector<ValueType> globals_;
471 : std::vector<uint8_t> mutable_globals_; // indexes into {globals_}.
472 : uint32_t recursion_depth = 0;
473 :
474 : static constexpr uint32_t kMaxRecursionDepth = 64;
475 :
476 : bool recursion_limit_reached() {
477 : return recursion_depth >= kMaxRecursionDepth;
478 : }
479 : };
480 :
481 : template <>
482 0 : void WasmGenerator::Generate<kWasmStmt>(DataRange& data) {
483 : GeneratorRecursionScope rec_scope(this);
484 0 : if (recursion_limit_reached() || data.size() == 0) return;
485 :
486 : constexpr generate_fn alternates[] = {
487 : &WasmGenerator::sequence<kWasmStmt, kWasmStmt>,
488 : &WasmGenerator::sequence<kWasmStmt, kWasmStmt, kWasmStmt, kWasmStmt>,
489 : &WasmGenerator::sequence<kWasmStmt, kWasmStmt, kWasmStmt, kWasmStmt,
490 : kWasmStmt, kWasmStmt, kWasmStmt, kWasmStmt>,
491 : &WasmGenerator::block<kWasmStmt>,
492 : &WasmGenerator::loop<kWasmStmt>,
493 : &WasmGenerator::if_<kWasmStmt, kIf>,
494 : &WasmGenerator::if_<kWasmStmt, kIfElse>,
495 : &WasmGenerator::br,
496 : &WasmGenerator::br_if<kWasmStmt>,
497 :
498 : &WasmGenerator::memop<kExprI32StoreMem, kWasmI32>,
499 : &WasmGenerator::memop<kExprI32StoreMem8, kWasmI32>,
500 : &WasmGenerator::memop<kExprI32StoreMem16, kWasmI32>,
501 : &WasmGenerator::memop<kExprI64StoreMem, kWasmI64>,
502 : &WasmGenerator::memop<kExprI64StoreMem8, kWasmI64>,
503 : &WasmGenerator::memop<kExprI64StoreMem16, kWasmI64>,
504 : &WasmGenerator::memop<kExprI64StoreMem32, kWasmI64>,
505 : &WasmGenerator::memop<kExprF32StoreMem, kWasmF32>,
506 : &WasmGenerator::memop<kExprF64StoreMem, kWasmF64>,
507 :
508 : &WasmGenerator::drop,
509 :
510 : &WasmGenerator::call<kWasmStmt>,
511 :
512 : &WasmGenerator::set_local,
513 0 : &WasmGenerator::set_global};
514 :
515 0 : GenerateOneOf(alternates, data);
516 : }
517 :
518 : template <>
519 1 : void WasmGenerator::Generate<kWasmI32>(DataRange& data) {
520 : GeneratorRecursionScope rec_scope(this);
521 2 : if (recursion_limit_reached() || data.size() <= 1) {
522 1 : builder_->EmitI32Const(data.get<uint32_t>());
523 1 : return;
524 : }
525 :
526 : constexpr generate_fn alternates[] = {
527 : &WasmGenerator::i32_const<1>,
528 : &WasmGenerator::i32_const<2>,
529 : &WasmGenerator::i32_const<3>,
530 : &WasmGenerator::i32_const<4>,
531 :
532 : &WasmGenerator::sequence<kWasmI32, kWasmStmt>,
533 : &WasmGenerator::sequence<kWasmStmt, kWasmI32>,
534 : &WasmGenerator::sequence<kWasmStmt, kWasmI32, kWasmStmt>,
535 :
536 : &WasmGenerator::op<kExprI32Eqz, kWasmI32>,
537 : &WasmGenerator::op<kExprI32Eq, kWasmI32, kWasmI32>,
538 : &WasmGenerator::op<kExprI32Ne, kWasmI32, kWasmI32>,
539 : &WasmGenerator::op<kExprI32LtS, kWasmI32, kWasmI32>,
540 : &WasmGenerator::op<kExprI32LtU, kWasmI32, kWasmI32>,
541 : &WasmGenerator::op<kExprI32GeS, kWasmI32, kWasmI32>,
542 : &WasmGenerator::op<kExprI32GeU, kWasmI32, kWasmI32>,
543 :
544 : &WasmGenerator::op<kExprI64Eqz, kWasmI64>,
545 : &WasmGenerator::op<kExprI64Eq, kWasmI64, kWasmI64>,
546 : &WasmGenerator::op<kExprI64Ne, kWasmI64, kWasmI64>,
547 : &WasmGenerator::op<kExprI64LtS, kWasmI64, kWasmI64>,
548 : &WasmGenerator::op<kExprI64LtU, kWasmI64, kWasmI64>,
549 : &WasmGenerator::op<kExprI64GeS, kWasmI64, kWasmI64>,
550 : &WasmGenerator::op<kExprI64GeU, kWasmI64, kWasmI64>,
551 :
552 : &WasmGenerator::op<kExprF32Eq, kWasmF32, kWasmF32>,
553 : &WasmGenerator::op<kExprF32Ne, kWasmF32, kWasmF32>,
554 : &WasmGenerator::op<kExprF32Lt, kWasmF32, kWasmF32>,
555 : &WasmGenerator::op<kExprF32Ge, kWasmF32, kWasmF32>,
556 :
557 : &WasmGenerator::op<kExprF64Eq, kWasmF64, kWasmF64>,
558 : &WasmGenerator::op<kExprF64Ne, kWasmF64, kWasmF64>,
559 : &WasmGenerator::op<kExprF64Lt, kWasmF64, kWasmF64>,
560 : &WasmGenerator::op<kExprF64Ge, kWasmF64, kWasmF64>,
561 :
562 : &WasmGenerator::op<kExprI32Add, kWasmI32, kWasmI32>,
563 : &WasmGenerator::op<kExprI32Sub, kWasmI32, kWasmI32>,
564 : &WasmGenerator::op<kExprI32Mul, kWasmI32, kWasmI32>,
565 :
566 : &WasmGenerator::op<kExprI32DivS, kWasmI32, kWasmI32>,
567 : &WasmGenerator::op<kExprI32DivU, kWasmI32, kWasmI32>,
568 : &WasmGenerator::op<kExprI32RemS, kWasmI32, kWasmI32>,
569 : &WasmGenerator::op<kExprI32RemU, kWasmI32, kWasmI32>,
570 :
571 : &WasmGenerator::op<kExprI32And, kWasmI32, kWasmI32>,
572 : &WasmGenerator::op<kExprI32Ior, kWasmI32, kWasmI32>,
573 : &WasmGenerator::op<kExprI32Xor, kWasmI32, kWasmI32>,
574 : &WasmGenerator::op<kExprI32Shl, kWasmI32, kWasmI32>,
575 : &WasmGenerator::op<kExprI32ShrU, kWasmI32, kWasmI32>,
576 : &WasmGenerator::op<kExprI32ShrS, kWasmI32, kWasmI32>,
577 : &WasmGenerator::op<kExprI32Ror, kWasmI32, kWasmI32>,
578 : &WasmGenerator::op<kExprI32Rol, kWasmI32, kWasmI32>,
579 :
580 : &WasmGenerator::op<kExprI32Clz, kWasmI32>,
581 : &WasmGenerator::op<kExprI32Ctz, kWasmI32>,
582 : &WasmGenerator::op<kExprI32Popcnt, kWasmI32>,
583 :
584 : &WasmGenerator::op<kExprI32ConvertI64, kWasmI64>,
585 : &WasmGenerator::op<kExprI32SConvertF32, kWasmF32>,
586 : &WasmGenerator::op<kExprI32UConvertF32, kWasmF32>,
587 : &WasmGenerator::op<kExprI32SConvertF64, kWasmF64>,
588 : &WasmGenerator::op<kExprI32UConvertF64, kWasmF64>,
589 : &WasmGenerator::op<kExprI32ReinterpretF32, kWasmF32>,
590 :
591 : &WasmGenerator::block<kWasmI32>,
592 : &WasmGenerator::loop<kWasmI32>,
593 : &WasmGenerator::if_<kWasmI32, kIfElse>,
594 : &WasmGenerator::br_if<kWasmI32>,
595 :
596 : &WasmGenerator::memop<kExprI32LoadMem>,
597 : &WasmGenerator::memop<kExprI32LoadMem8S>,
598 : &WasmGenerator::memop<kExprI32LoadMem8U>,
599 : &WasmGenerator::memop<kExprI32LoadMem16S>,
600 : &WasmGenerator::memop<kExprI32LoadMem16U>,
601 :
602 : &WasmGenerator::current_memory,
603 : &WasmGenerator::grow_memory,
604 :
605 : &WasmGenerator::get_local<kWasmI32>,
606 : &WasmGenerator::tee_local<kWasmI32>,
607 : &WasmGenerator::get_global<kWasmI32>,
608 :
609 0 : &WasmGenerator::call<kWasmI32>};
610 :
611 0 : GenerateOneOf(alternates, data);
612 : }
613 :
614 : template <>
615 0 : void WasmGenerator::Generate<kWasmI64>(DataRange& data) {
616 : GeneratorRecursionScope rec_scope(this);
617 0 : if (recursion_limit_reached() || data.size() <= 1) {
618 0 : builder_->EmitI64Const(data.get<int64_t>());
619 0 : return;
620 : }
621 :
622 : constexpr generate_fn alternates[] = {
623 : &WasmGenerator::i64_const<1>,
624 : &WasmGenerator::i64_const<2>,
625 : &WasmGenerator::i64_const<3>,
626 : &WasmGenerator::i64_const<4>,
627 : &WasmGenerator::i64_const<5>,
628 : &WasmGenerator::i64_const<6>,
629 : &WasmGenerator::i64_const<7>,
630 : &WasmGenerator::i64_const<8>,
631 :
632 : &WasmGenerator::sequence<kWasmI64, kWasmStmt>,
633 : &WasmGenerator::sequence<kWasmStmt, kWasmI64>,
634 : &WasmGenerator::sequence<kWasmStmt, kWasmI64, kWasmStmt>,
635 :
636 : &WasmGenerator::op<kExprI64Add, kWasmI64, kWasmI64>,
637 : &WasmGenerator::op<kExprI64Sub, kWasmI64, kWasmI64>,
638 : &WasmGenerator::op<kExprI64Mul, kWasmI64, kWasmI64>,
639 :
640 : &WasmGenerator::op<kExprI64DivS, kWasmI64, kWasmI64>,
641 : &WasmGenerator::op<kExprI64DivU, kWasmI64, kWasmI64>,
642 : &WasmGenerator::op<kExprI64RemS, kWasmI64, kWasmI64>,
643 : &WasmGenerator::op<kExprI64RemU, kWasmI64, kWasmI64>,
644 :
645 : &WasmGenerator::op<kExprI64And, kWasmI64, kWasmI64>,
646 : &WasmGenerator::op<kExprI64Ior, kWasmI64, kWasmI64>,
647 : &WasmGenerator::op<kExprI64Xor, kWasmI64, kWasmI64>,
648 : &WasmGenerator::op<kExprI64Shl, kWasmI64, kWasmI64>,
649 : &WasmGenerator::op<kExprI64ShrU, kWasmI64, kWasmI64>,
650 : &WasmGenerator::op<kExprI64ShrS, kWasmI64, kWasmI64>,
651 : &WasmGenerator::op<kExprI64Ror, kWasmI64, kWasmI64>,
652 : &WasmGenerator::op<kExprI64Rol, kWasmI64, kWasmI64>,
653 :
654 : &WasmGenerator::op<kExprI64Clz, kWasmI64>,
655 : &WasmGenerator::op<kExprI64Ctz, kWasmI64>,
656 : &WasmGenerator::op<kExprI64Popcnt, kWasmI64>,
657 :
658 : &WasmGenerator::block<kWasmI64>,
659 : &WasmGenerator::loop<kWasmI64>,
660 : &WasmGenerator::if_<kWasmI64, kIfElse>,
661 : &WasmGenerator::br_if<kWasmI64>,
662 :
663 : &WasmGenerator::memop<kExprI64LoadMem>,
664 : &WasmGenerator::memop<kExprI64LoadMem8S>,
665 : &WasmGenerator::memop<kExprI64LoadMem8U>,
666 : &WasmGenerator::memop<kExprI64LoadMem16S>,
667 : &WasmGenerator::memop<kExprI64LoadMem16U>,
668 : &WasmGenerator::memop<kExprI64LoadMem32S>,
669 : &WasmGenerator::memop<kExprI64LoadMem32U>,
670 :
671 : &WasmGenerator::get_local<kWasmI64>,
672 : &WasmGenerator::tee_local<kWasmI64>,
673 : &WasmGenerator::get_global<kWasmI64>,
674 :
675 0 : &WasmGenerator::call<kWasmI64>};
676 :
677 0 : GenerateOneOf(alternates, data);
678 : }
679 :
680 : template <>
681 0 : void WasmGenerator::Generate<kWasmF32>(DataRange& data) {
682 : GeneratorRecursionScope rec_scope(this);
683 0 : if (recursion_limit_reached() || data.size() <= sizeof(float)) {
684 0 : builder_->EmitF32Const(data.get<float>());
685 0 : return;
686 : }
687 :
688 : constexpr generate_fn alternates[] = {
689 : &WasmGenerator::sequence<kWasmF32, kWasmStmt>,
690 : &WasmGenerator::sequence<kWasmStmt, kWasmF32>,
691 : &WasmGenerator::sequence<kWasmStmt, kWasmF32, kWasmStmt>,
692 :
693 : &WasmGenerator::op<kExprF32Add, kWasmF32, kWasmF32>,
694 : &WasmGenerator::op<kExprF32Sub, kWasmF32, kWasmF32>,
695 : &WasmGenerator::op<kExprF32Mul, kWasmF32, kWasmF32>,
696 :
697 : &WasmGenerator::block<kWasmF32>,
698 : &WasmGenerator::loop<kWasmF32>,
699 : &WasmGenerator::if_<kWasmF32, kIfElse>,
700 : &WasmGenerator::br_if<kWasmF32>,
701 :
702 : &WasmGenerator::memop<kExprF32LoadMem>,
703 :
704 : &WasmGenerator::get_local<kWasmF32>,
705 : &WasmGenerator::tee_local<kWasmF32>,
706 : &WasmGenerator::get_global<kWasmF32>,
707 :
708 0 : &WasmGenerator::call<kWasmF32>};
709 :
710 0 : GenerateOneOf(alternates, data);
711 : }
712 :
713 : template <>
714 0 : void WasmGenerator::Generate<kWasmF64>(DataRange& data) {
715 : GeneratorRecursionScope rec_scope(this);
716 0 : if (recursion_limit_reached() || data.size() <= sizeof(double)) {
717 0 : builder_->EmitF64Const(data.get<double>());
718 0 : return;
719 : }
720 :
721 : constexpr generate_fn alternates[] = {
722 : &WasmGenerator::sequence<kWasmF64, kWasmStmt>,
723 : &WasmGenerator::sequence<kWasmStmt, kWasmF64>,
724 : &WasmGenerator::sequence<kWasmStmt, kWasmF64, kWasmStmt>,
725 :
726 : &WasmGenerator::op<kExprF64Add, kWasmF64, kWasmF64>,
727 : &WasmGenerator::op<kExprF64Sub, kWasmF64, kWasmF64>,
728 : &WasmGenerator::op<kExprF64Mul, kWasmF64, kWasmF64>,
729 :
730 : &WasmGenerator::block<kWasmF64>,
731 : &WasmGenerator::loop<kWasmF64>,
732 : &WasmGenerator::if_<kWasmF64, kIfElse>,
733 : &WasmGenerator::br_if<kWasmF64>,
734 :
735 : &WasmGenerator::memop<kExprF64LoadMem>,
736 :
737 : &WasmGenerator::get_local<kWasmF64>,
738 : &WasmGenerator::tee_local<kWasmF64>,
739 : &WasmGenerator::get_global<kWasmF64>,
740 :
741 0 : &WasmGenerator::call<kWasmF64>};
742 :
743 0 : GenerateOneOf(alternates, data);
744 : }
745 :
746 0 : void WasmGenerator::grow_memory(DataRange& data) {
747 0 : Generate<kWasmI32>(data);
748 0 : builder_->EmitWithU8(kExprMemoryGrow, 0);
749 0 : }
750 :
751 1 : void WasmGenerator::Generate(ValueType type, DataRange& data) {
752 1 : switch (type) {
753 : case kWasmStmt:
754 0 : return Generate<kWasmStmt>(data);
755 : case kWasmI32:
756 1 : return Generate<kWasmI32>(data);
757 : case kWasmI64:
758 0 : return Generate<kWasmI64>(data);
759 : case kWasmF32:
760 0 : return Generate<kWasmF32>(data);
761 : case kWasmF64:
762 0 : return Generate<kWasmF64>(data);
763 : default:
764 0 : UNREACHABLE();
765 : }
766 : }
767 :
768 0 : FunctionSig* GenerateSig(Zone* zone, DataRange& data) {
769 : // Generate enough parameters to spill some to the stack.
770 : constexpr int kMaxParameters = 15;
771 0 : int num_params = int{data.get<uint8_t>()} % (kMaxParameters + 1);
772 0 : bool has_return = data.get<bool>();
773 :
774 0 : FunctionSig::Builder builder(zone, has_return ? 1 : 0, num_params);
775 0 : if (has_return) builder.AddReturn(GetValueType(data));
776 0 : for (int i = 0; i < num_params; ++i) builder.AddParam(GetValueType(data));
777 0 : return builder.Build();
778 : }
779 :
780 : } // namespace
781 :
782 1 : class WasmCompileFuzzer : public WasmExecutionFuzzer {
783 1 : bool GenerateModule(
784 : Isolate* isolate, Zone* zone, Vector<const uint8_t> data,
785 : ZoneBuffer& buffer, int32_t& num_args,
786 : std::unique_ptr<WasmValue[]>& interpreter_args,
787 : std::unique_ptr<Handle<Object>[]>& compiler_args) override {
788 1 : TestSignatures sigs;
789 :
790 1 : WasmModuleBuilder builder(zone);
791 :
792 : DataRange range(data);
793 : std::vector<FunctionSig*> function_signatures;
794 2 : function_signatures.push_back(sigs.i_iii());
795 :
796 : static_assert(kMaxFunctions >= 1, "need min. 1 function");
797 1 : int num_functions = 1 + (range.get<uint8_t>() % kMaxFunctions);
798 :
799 1 : for (int i = 1; i < num_functions; ++i) {
800 0 : function_signatures.push_back(GenerateSig(zone, range));
801 : }
802 :
803 1 : int num_globals = range.get<uint8_t>() % (kMaxGlobals + 1);
804 : std::vector<ValueType> globals;
805 : std::vector<uint8_t> mutable_globals;
806 1 : globals.reserve(num_globals);
807 1 : mutable_globals.reserve(num_globals);
808 :
809 1 : for (int i = 0; i < num_globals; ++i) {
810 0 : ValueType type = GetValueType(range);
811 0 : const bool exported = range.get<bool>();
812 : // 1/8 of globals are immutable.
813 0 : const bool mutability = (range.get<uint8_t>() % 8) != 0;
814 0 : builder.AddGlobal(type, exported, mutability, WasmInitExpr());
815 0 : globals.push_back(type);
816 0 : if (mutability) mutable_globals.push_back(static_cast<uint8_t>(i));
817 : }
818 :
819 1 : for (int i = 0; i < num_functions; ++i) {
820 : DataRange function_range =
821 1 : i == num_functions - 1 ? std::move(range) : range.split();
822 :
823 4 : FunctionSig* sig = function_signatures[i];
824 1 : WasmFunctionBuilder* f = builder.AddFunction(sig);
825 :
826 : WasmGenerator gen(f, function_signatures, globals, mutable_globals,
827 1 : function_range);
828 : ValueType return_type =
829 1 : sig->return_count() == 0 ? kWasmStmt : sig->GetReturn(0);
830 1 : gen.Generate(return_type, function_range);
831 :
832 1 : f->Emit(kExprEnd);
833 1 : if (i == 0) builder.AddExport(CStrVector("main"), f);
834 1 : }
835 :
836 1 : builder.SetMaxMemorySize(32);
837 1 : builder.WriteTo(buffer);
838 :
839 1 : num_args = 3;
840 : interpreter_args.reset(
841 1 : new WasmValue[3]{WasmValue(1), WasmValue(2), WasmValue(3)});
842 :
843 : compiler_args.reset(new Handle<Object>[3]{
844 : handle(Smi::FromInt(1), isolate), handle(Smi::FromInt(2), isolate),
845 1 : handle(Smi::FromInt(3), isolate)});
846 1 : return true;
847 : }
848 : };
849 :
850 1 : extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
851 : constexpr bool require_valid = true;
852 2 : WasmCompileFuzzer().FuzzWasmModule({data, size}, require_valid);
853 1 : return 0;
854 : }
855 :
856 : } // namespace fuzzer
857 : } // namespace wasm
858 : } // namespace internal
859 3 : } // namespace v8
|