LCOV - code coverage report
Current view: top level - test/fuzzer - wasm-compile.cc (source / functions) Hit Total Coverage
Test: app.info Lines: 55 269 20.4 %
Date: 2019-02-19 Functions: 10 247 4.0 %

          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

Generated by: LCOV version 1.10