LCOV - code coverage report
Current view: top level - test/fuzzer - wasm-compile.cc (source / functions) Hit Total Coverage
Test: app.info Lines: 51 262 19.5 %
Date: 2019-04-17 Functions: 9 245 3.7 %

          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

Generated by: LCOV version 1.10