LCOV - code coverage report
Current view: top level - test/fuzzer - wasm-compile.cc (source / functions) Hit Total Coverage
Test: app.info Lines: 25 90 27.8 %
Date: 2017-10-20 Functions: 4 97 4.1 %

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

Generated by: LCOV version 1.10