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