|  | // Copyright 2016 the V8 project authors. All rights reserved. | 
|  | // Use of this source code is governed by a BSD-style license that can be | 
|  | // found in the LICENSE file. | 
|  |  | 
|  | #include <stddef.h> | 
|  | #include <stdint.h> | 
|  |  | 
|  | #include "include/v8.h" | 
|  | #include "src/isolate.h" | 
|  | #include "src/objects-inl.h" | 
|  | #include "src/objects.h" | 
|  | #include "src/utils.h" | 
|  | #include "src/wasm/wasm-interpreter.h" | 
|  | #include "src/wasm/wasm-module-builder.h" | 
|  | #include "src/wasm/wasm-module.h" | 
|  | #include "test/common/wasm/test-signatures.h" | 
|  | #include "test/common/wasm/wasm-module-runner.h" | 
|  | #include "test/fuzzer/fuzzer-support.h" | 
|  | #include "test/fuzzer/wasm-fuzzer-common.h" | 
|  |  | 
|  | namespace v8 { | 
|  | namespace internal { | 
|  | namespace wasm { | 
|  | namespace fuzzer { | 
|  |  | 
|  | static constexpr uint32_t kMaxNumFunctions = 3; | 
|  | static constexpr uint32_t kMaxNumParams = 3; | 
|  |  | 
|  | class WasmCallFuzzer : public WasmExecutionFuzzer { | 
|  | template <typename V> | 
|  | static inline V read_value(const uint8_t** data, size_t* size, bool* ok) { | 
|  | // The status flag {ok} checks that the decoding up until now was okay, and | 
|  | // that a value of type V can be read without problems. | 
|  | *ok &= (*size > sizeof(V)); | 
|  | if (!(*ok)) return 0; | 
|  | V result = ReadLittleEndianValue<V>(*data); | 
|  | *data += sizeof(V); | 
|  | *size -= sizeof(V); | 
|  | return result; | 
|  | } | 
|  |  | 
|  | static void add_argument(Isolate* isolate, ValueType type, | 
|  | WasmValue* interpreter_args, | 
|  | Handle<Object>* compiler_args, int* argc, | 
|  | const uint8_t** data, size_t* size, bool* ok) { | 
|  | if (!(*ok)) return; | 
|  | switch (type) { | 
|  | case kWasmF32: { | 
|  | float value = read_value<float>(data, size, ok); | 
|  | interpreter_args[*argc] = WasmValue(value); | 
|  | compiler_args[*argc] = | 
|  | isolate->factory()->NewNumber(static_cast<double>(value)); | 
|  | break; | 
|  | } | 
|  | case kWasmF64: { | 
|  | double value = read_value<double>(data, size, ok); | 
|  | interpreter_args[*argc] = WasmValue(value); | 
|  | compiler_args[*argc] = isolate->factory()->NewNumber(value); | 
|  | break; | 
|  | } | 
|  | case kWasmI32: { | 
|  | int32_t value = read_value<int32_t>(data, size, ok); | 
|  | interpreter_args[*argc] = WasmValue(value); | 
|  | compiler_args[*argc] = | 
|  | isolate->factory()->NewNumber(static_cast<double>(value)); | 
|  | break; | 
|  | } | 
|  | default: | 
|  | UNREACHABLE(); | 
|  | } | 
|  | (*argc)++; | 
|  | } | 
|  |  | 
|  | bool GenerateModule( | 
|  | Isolate* isolate, Zone* zone, const uint8_t* data, size_t size, | 
|  | ZoneBuffer& buffer, int32_t& num_args, | 
|  | std::unique_ptr<WasmValue[]>& interpreter_args, | 
|  | std::unique_ptr<Handle<Object>[]>& compiler_args) override { | 
|  | bool ok = true; | 
|  | uint8_t num_functions = | 
|  | (read_value<uint8_t>(&data, &size, &ok) % kMaxNumFunctions) + 1; | 
|  |  | 
|  | ValueType types[] = {kWasmF32, kWasmF64, kWasmI32, kWasmI64}; | 
|  |  | 
|  | interpreter_args.reset(new WasmValue[3]); | 
|  | compiler_args.reset(new Handle<Object>[3]); | 
|  |  | 
|  | WasmModuleBuilder builder(zone); | 
|  | for (int fun = 0; fun < num_functions; fun++) { | 
|  | size_t num_params = static_cast<size_t>( | 
|  | (read_value<uint8_t>(&data, &size, &ok) % kMaxNumParams) + 1); | 
|  | FunctionSig::Builder sig_builder(zone, 1, num_params); | 
|  | sig_builder.AddReturn(kWasmI32); | 
|  | for (size_t param = 0; param < num_params; param++) { | 
|  | // The main function cannot handle int64 parameters. | 
|  | ValueType param_type = types[(read_value<uint8_t>(&data, &size, &ok) % | 
|  | (arraysize(types) - (fun == 0 ? 1 : 0)))]; | 
|  | sig_builder.AddParam(param_type); | 
|  | if (fun == 0) { | 
|  | add_argument(isolate, param_type, interpreter_args.get(), | 
|  | compiler_args.get(), &num_args, &data, &size, &ok); | 
|  | } | 
|  | } | 
|  | WasmFunctionBuilder* f = builder.AddFunction(sig_builder.Build()); | 
|  | uint32_t code_size = static_cast<uint32_t>(size / num_functions); | 
|  | f->EmitCode(data, code_size); | 
|  | uint8_t end_opcode = kExprEnd; | 
|  | f->EmitCode(&end_opcode, 1); | 
|  | data += code_size; | 
|  | size -= code_size; | 
|  | if (fun == 0) { | 
|  | builder.AddExport(CStrVector("main"), f); | 
|  | } | 
|  | } | 
|  |  | 
|  | builder.SetMaxMemorySize(32); | 
|  | builder.WriteTo(buffer); | 
|  |  | 
|  | if (!ok) { | 
|  | // The input data was too short. | 
|  | return 0; | 
|  | } | 
|  | return true; | 
|  | } | 
|  | }; | 
|  |  | 
|  | extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) { | 
|  | return WasmCallFuzzer().FuzzWasmModule(data, size); | 
|  | } | 
|  |  | 
|  | }  // namespace fuzzer | 
|  | }  // namespace wasm | 
|  | }  // namespace internal | 
|  | }  // namespace v8 |