diff options
author | Michaël Zasso <targos@protonmail.com> | 2017-05-02 10:50:00 +0200 |
---|---|---|
committer | Michaël Zasso <targos@protonmail.com> | 2017-05-06 20:02:35 +0200 |
commit | 60d1aac8d225e844e68ae48e8f3d58802e635fbe (patch) | |
tree | 922f347dd054db18d88666fad7181e5a777f4022 /deps/v8/test/fuzzer | |
parent | 73d9c0f903ae371cd5011af64c3a6f69a1bda978 (diff) | |
download | node-new-60d1aac8d225e844e68ae48e8f3d58802e635fbe.tar.gz |
deps: update V8 to 5.8.283.38
PR-URL: https://github.com/nodejs/node/pull/12784
Reviewed-By: Ben Noordhuis <info@bnoordhuis.nl>
Reviewed-By: Gibson Fahnestock <gibfahn@gmail.com>
Diffstat (limited to 'deps/v8/test/fuzzer')
-rw-r--r-- | deps/v8/test/fuzzer/README.md | 91 | ||||
-rw-r--r-- | deps/v8/test/fuzzer/fuzzer.gyp | 29 | ||||
-rw-r--r-- | deps/v8/test/fuzzer/fuzzer.isolate | 2 | ||||
-rw-r--r-- | deps/v8/test/fuzzer/parser.cc | 3 | ||||
-rw-r--r-- | deps/v8/test/fuzzer/testcfg.py | 7 | ||||
-rw-r--r-- | deps/v8/test/fuzzer/wasm-asmjs.cc | 6 | ||||
-rw-r--r-- | deps/v8/test/fuzzer/wasm-call.cc | 15 | ||||
-rw-r--r-- | deps/v8/test/fuzzer/wasm-code.cc | 13 | ||||
-rw-r--r-- | deps/v8/test/fuzzer/wasm-compile.cc | 447 | ||||
-rw-r--r-- | deps/v8/test/fuzzer/wasm-data-section.cc | 1 | ||||
-rw-r--r-- | deps/v8/test/fuzzer/wasm-function-sigs-section.cc | 1 | ||||
-rw-r--r-- | deps/v8/test/fuzzer/wasm-globals-section.cc | 1 | ||||
-rw-r--r-- | deps/v8/test/fuzzer/wasm-imports-section.cc | 1 | ||||
-rw-r--r-- | deps/v8/test/fuzzer/wasm-memory-section.cc | 1 | ||||
-rw-r--r-- | deps/v8/test/fuzzer/wasm-names-section.cc | 1 | ||||
-rw-r--r-- | deps/v8/test/fuzzer/wasm-section-fuzzers.cc | 1 | ||||
-rw-r--r-- | deps/v8/test/fuzzer/wasm-section-fuzzers.h | 2 | ||||
-rw-r--r-- | deps/v8/test/fuzzer/wasm-types-section.cc | 1 | ||||
-rw-r--r-- | deps/v8/test/fuzzer/wasm.cc | 6 | ||||
-rw-r--r-- | deps/v8/test/fuzzer/wasm_compile/foo | 0 |
20 files changed, 616 insertions, 13 deletions
diff --git a/deps/v8/test/fuzzer/README.md b/deps/v8/test/fuzzer/README.md new file mode 100644 index 0000000000..ed0ce1fa2a --- /dev/null +++ b/deps/v8/test/fuzzer/README.md @@ -0,0 +1,91 @@ +# How to make a libFuzzer fuzzer in V8 + +This document describes how to make a new libFuzzer fuzzer for V8. A general +introduction to libFuzzer can be found +[here](https://chromium.googlesource.com/chromium/src/+/master/testing/libfuzzer/README.md). +In short, libFuzzer is an in-process coverage-driven evolutionary fuzzer. +libFuzzer serves you with a sequence of byte arrays that you can use to test +your code. libFuzzer tries to generate this sequence of byte arrays in a way +that maximizes test coverage. + +**Warning**: By itself libFuzzer typically does not generate valid JavaScript code. + +## Changes to V8 + +**tldr:** Do the same as https://codereview.chromium.org/2280623002 to introduce +a new fuzzer to V8. + +This is a step by step guide on how to make a new fuzzer in V8. In the example +the fuzzer is called `foo`. + +1. Copy one of the existing fuzzer implementations in + [test/fuzzer/](https://cs.chromium.org/chromium/src/v8/test/fuzzer/), e.g. `cp wasm.cc foo.cc` + + * Copying an existing fuzzer is a good idea to get all the required setup, + e.g. setting up the isolate + +2. Create a directory called `foo` in + [test/fuzzer/](https://cs.chromium.org/chromium/src/v8/test/fuzzer/) which + contains at least one file + + * The file is used by the trybots to check whether the fuzzer actually + compiles and runs + +3. Copy the build rules of an existing fuzzer in + [BUILD.gn](https://cs.chromium.org/chromium/src/v8/BUILD.gn), e.g. the build + rules for the + [wasm.cc](https://cs.chromium.org/chromium/src/v8/test/fuzzer/wasm.cc) fuzzer + are `v8_source_set("wasm_fuzzer")` and `v8_fuzzer("wasm_fuzzer")`. Note that + the name has to be the name of the directory created in Step 2 + `_fuzzer` so + that the scripts on the trybots work + +4. Now you can already compile the fuzzer, e.g. with `ninja -j 1000 -C + out/x64.debug/v8_simple_foo_fuzzer` + + * Use this binary to reproduce issues found by cluster fuzz, e.g. + `out/x64.debug/v8_simple_foo_fuzzer testcase.foo` + +5. Copy the build rules of an existing fuzzer in + [test/fuzzer/fuzzer.gyp](https://cs.chromium.org/chromium/src/v8/test/fuzzer/fuzzer.gyp), + e.g. the build rules for the + [wasm.cc](https://cs.chromium.org/chromium/src/v8/test/fuzzer/wasm.cc) fuzzer + are `v8_simple_wasm_fuzzer` and `wasm_fuzzer_lib` + + * This build rule is needed to compile with gyp + +6. Copy the binary name and the test directory name in + [test/fuzzer/fuzzer.isolate](https://cs.chromium.org/chromium/src/v8/test/fuzzer/fuzzer.isolate) + +7. Add the fuzzer to the FuzzerTestSuite in + [test/fuzzer/testcfg.py](https://cs.chromium.org/chromium/src/v8/test/fuzzer/testcfg.py) + + * This step is needed to run the fuzzer with the files created in Step 2 on + the trybots + +8. Commit the changes described above to the V8 repository + +## Changes to Chromium + +**tldr:** Do the same as https://codereview.chromium.org/2344823002 to add the +new fuzzer to cluster fuzz. + +1. Copy the build rules of an existing fuzzer in + [testing/libfuzzer/fuzzers/BUILD.gn](https://cs.chromium.org/chromium/src/testing/libfuzzer/fuzzers/BUILD.gn), + e.g. the build rule for the + [wasm.cc](https://cs.chromium.org/chromium/src/v8/test/fuzzer/wasm.cc) fuzzer + is `v8_wasm_fuzzer`. There is no need to set a `dictionary` , or a `seed_corpus`. + See + [chromium-fuzzing-getting-started](https://chromium.googlesource.com/chromium/src/+/master/testing/libfuzzer/getting_started.md) + for more information. + +2. Compile the fuzzer in chromium (for different configurations see: + https://chromium.googlesource.com/chromium/src/+/master/testing/libfuzzer/reproducing.md): + + * `gn gen out/libfuzzer '--args=use_libfuzzer=true is_asan=true is_debug=false enable_nacl=false'` + + * `ninja -j 1000 -C out/libfuzzer/ v8_foo_fuzzer` + +3. Run the fuzzer locally + + * `mkdir /tmp/empty_corpus && out/libfuzzer/v8_foo_fuzzer /tmp/empty_corpus` + diff --git a/deps/v8/test/fuzzer/fuzzer.gyp b/deps/v8/test/fuzzer/fuzzer.gyp index 6b40aaaf54..3b93808533 100644 --- a/deps/v8/test/fuzzer/fuzzer.gyp +++ b/deps/v8/test/fuzzer/fuzzer.gyp @@ -201,6 +201,35 @@ ], }, { + 'target_name': 'v8_simple_wasm_compile_fuzzer', + 'type': 'executable', + 'dependencies': [ + 'wasm_compile_fuzzer_lib', + ], + 'include_dirs': [ + '../..', + ], + 'sources': [ + 'fuzzer.cc', + ], + }, + { + 'target_name': 'wasm_compile_fuzzer_lib', + 'type': 'static_library', + 'dependencies': [ + 'fuzzer_support', + ], + 'include_dirs': [ + '../..', + ], + 'sources': [ ### gcmole(all) ### + 'wasm-compile.cc', + '../common/wasm/test-signatures.h', + '../common/wasm/wasm-module-runner.cc', + '../common/wasm/wasm-module-runner.h', + ], + }, + { 'target_name': 'v8_simple_wasm_data_section_fuzzer', 'type': 'executable', 'dependencies': [ diff --git a/deps/v8/test/fuzzer/fuzzer.isolate b/deps/v8/test/fuzzer/fuzzer.isolate index 788c76c010..5a4654c155 100644 --- a/deps/v8/test/fuzzer/fuzzer.isolate +++ b/deps/v8/test/fuzzer/fuzzer.isolate @@ -12,6 +12,7 @@ '<(PRODUCT_DIR)/v8_simple_wasm_asmjs_fuzzer<(EXECUTABLE_SUFFIX)', '<(PRODUCT_DIR)/v8_simple_wasm_call_fuzzer<(EXECUTABLE_SUFFIX)', '<(PRODUCT_DIR)/v8_simple_wasm_code_fuzzer<(EXECUTABLE_SUFFIX)', + '<(PRODUCT_DIR)/v8_simple_wasm_compile_fuzzer<(EXECUTABLE_SUFFIX)', '<(PRODUCT_DIR)/v8_simple_wasm_data_section_fuzzer<(EXECUTABLE_SUFFIX)', '<(PRODUCT_DIR)/v8_simple_wasm_function_sigs_section_fuzzer<(EXECUTABLE_SUFFIX)', '<(PRODUCT_DIR)/v8_simple_wasm_globals_section_fuzzer<(EXECUTABLE_SUFFIX)', @@ -28,6 +29,7 @@ './wasm_asmjs/', './wasm_call/', './wasm_code/', + './wasm_compile/', './wasm_data_section/', './wasm_function_sigs_section/', './wasm_globals_section/', diff --git a/deps/v8/test/fuzzer/parser.cc b/deps/v8/test/fuzzer/parser.cc index 4ce4acb8bd..2b31bf5aab 100644 --- a/deps/v8/test/fuzzer/parser.cc +++ b/deps/v8/test/fuzzer/parser.cc @@ -35,8 +35,7 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) { v8::internal::Handle<v8::internal::Script> script = factory->NewScript(source.ToHandleChecked()); - v8::internal::Zone zone(i_isolate->allocator(), ZONE_NAME); - v8::internal::ParseInfo info(&zone, script); + v8::internal::ParseInfo info(script); v8::internal::parsing::ParseProgram(&info); isolate->RequestGarbageCollectionForTesting( v8::Isolate::kFullGarbageCollection); diff --git a/deps/v8/test/fuzzer/testcfg.py b/deps/v8/test/fuzzer/testcfg.py index 0e4925bc06..0e07fb574e 100644 --- a/deps/v8/test/fuzzer/testcfg.py +++ b/deps/v8/test/fuzzer/testcfg.py @@ -19,9 +19,10 @@ class FuzzerVariantGenerator(testsuite.VariantGenerator): class FuzzerTestSuite(testsuite.TestSuite): SUB_TESTS = ( 'json', 'parser', 'regexp', 'wasm', 'wasm_asmjs', 'wasm_call', - 'wasm_code', 'wasm_data_section', 'wasm_function_sigs_section', - 'wasm_globals_section', 'wasm_imports_section', 'wasm_memory_section', - 'wasm_names_section', 'wasm_types_section' ) + 'wasm_code', 'wasm_compile', 'wasm_data_section', + 'wasm_function_sigs_section', 'wasm_globals_section', + 'wasm_imports_section', 'wasm_memory_section', 'wasm_names_section', + 'wasm_types_section' ) def __init__(self, name, root): super(FuzzerTestSuite, self).__init__(name, root) diff --git a/deps/v8/test/fuzzer/wasm-asmjs.cc b/deps/v8/test/fuzzer/wasm-asmjs.cc index d3341fa5b3..2f35ded7e3 100644 --- a/deps/v8/test/fuzzer/wasm-asmjs.cc +++ b/deps/v8/test/fuzzer/wasm-asmjs.cc @@ -17,6 +17,10 @@ #include "test/fuzzer/fuzzer-support.h" extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) { + unsigned int max_mem_flag_value = v8::internal::FLAG_wasm_max_mem_pages; + unsigned int max_table_flag_value = v8::internal::FLAG_wasm_max_table_size; + v8::internal::FLAG_wasm_max_mem_pages = 32; + v8::internal::FLAG_wasm_max_table_size = 100; v8_fuzzer::FuzzerSupport* support = v8_fuzzer::FuzzerSupport::Get(); v8::Isolate* isolate = support->GetIsolate(); v8::internal::Isolate* i_isolate = @@ -35,5 +39,7 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) { v8::internal::wasm::testing::CompileAndRunWasmModule( i_isolate, data, data + size, v8::internal::wasm::ModuleOrigin::kAsmJsOrigin); + v8::internal::FLAG_wasm_max_mem_pages = max_mem_flag_value; + v8::internal::FLAG_wasm_max_table_size = max_table_flag_value; return 0; } diff --git a/deps/v8/test/fuzzer/wasm-call.cc b/deps/v8/test/fuzzer/wasm-call.cc index e18575c5d6..3291d9eab1 100644 --- a/deps/v8/test/fuzzer/wasm-call.cc +++ b/deps/v8/test/fuzzer/wasm-call.cc @@ -7,6 +7,7 @@ #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" @@ -168,15 +169,19 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) { i_isolate, instance, &compiler_thrower, "main", argc, compiled_args, v8::internal::wasm::ModuleOrigin::kWasmOrigin); } + + // The WebAssembly spec allows the sign bit of NaN to be non-deterministic. + // This sign bit may cause result_interpreted to be different than + // result_compiled. Therefore we do not check the equality of the results + // if the execution may have produced a NaN at some point. + if (possible_nondeterminism) return 0; + if (result_interpreted == bit_cast<int32_t>(0xdeadbeef)) { CHECK(i_isolate->has_pending_exception()); i_isolate->clear_pending_exception(); } else { - // The WebAssembly spec allows the sign bit of NaN to be non-deterministic. - // This sign bit may cause result_interpreted to be different than - // result_compiled. Therefore we do not check the equality of the results - // if the execution may have produced a NaN at some point. - if (!possible_nondeterminism && (result_interpreted != result_compiled)) { + CHECK(!i_isolate->has_pending_exception()); + if (result_interpreted != result_compiled) { V8_Fatal(__FILE__, __LINE__, "WasmCodeFuzzerHash=%x", v8::internal::StringHasher::HashSequentialString( data, static_cast<int>(size), WASM_CODE_FUZZER_HASH_SEED)); diff --git a/deps/v8/test/fuzzer/wasm-code.cc b/deps/v8/test/fuzzer/wasm-code.cc index 167680faf2..a80cfcfaca 100644 --- a/deps/v8/test/fuzzer/wasm-code.cc +++ b/deps/v8/test/fuzzer/wasm-code.cc @@ -7,6 +7,7 @@ #include "include/v8.h" #include "src/isolate.h" +#include "src/objects-inl.h" #include "src/objects.h" #include "src/ostreams.h" #include "src/wasm/wasm-interpreter.h" @@ -38,7 +39,7 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) { os << std::endl; os << "(function() {" << std::endl; os << " var builder = new WasmModuleBuilder();" << std::endl; - os << " builder.addMemory(32, 32, false);" << std::endl; + os << " builder.addMemory(16, 32, false);" << std::endl; os << " builder.addFunction(\"test\", kSig_i_iii)" << std::endl; os << " .addBodyWithEnd([" << std::endl; } @@ -136,15 +137,23 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) { i_isolate, instance, &compiler_thrower, "main", arraysize(arguments), arguments, v8::internal::wasm::ModuleOrigin::kWasmOrigin); } + + // The WebAssembly spec allows the sign bit of NaN to be non-deterministic. + // This sign bit may cause result_interpreted to be different than + // result_compiled. Therefore we do not check the equality of the results + // if the execution may have produced a NaN at some point. + if (possible_nondeterminism) return 0; + if (result_interpreted == bit_cast<int32_t>(0xdeadbeef)) { CHECK(i_isolate->has_pending_exception()); i_isolate->clear_pending_exception(); } else { + CHECK(!i_isolate->has_pending_exception()); // The WebAssembly spec allows the sign bit of NaN to be non-deterministic. // This sign bit may cause result_interpreted to be different than // result_compiled. Therefore we do not check the equality of the results // if the execution may have produced a NaN at some point. - if (!possible_nondeterminism && (result_interpreted != result_compiled)) { + if (result_interpreted != result_compiled) { V8_Fatal(__FILE__, __LINE__, "WasmCodeFuzzerHash=%x", v8::internal::StringHasher::HashSequentialString( data, static_cast<int>(size), WASM_CODE_FUZZER_HASH_SEED)); diff --git a/deps/v8/test/fuzzer/wasm-compile.cc b/deps/v8/test/fuzzer/wasm-compile.cc new file mode 100644 index 0000000000..0b01ce2357 --- /dev/null +++ b/deps/v8/test/fuzzer/wasm-compile.cc @@ -0,0 +1,447 @@ +// Copyright 2017 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 <stdlib.h> + +#include <algorithm> + +#include "include/v8.h" +#include "src/isolate.h" +#include "src/objects-inl.h" +#include "src/objects.h" +#include "src/ostreams.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" + +#define WASM_CODE_FUZZER_HASH_SEED 83 + +typedef uint8_t byte; + +using namespace v8::internal::wasm; + +namespace { + +class DataRange { + const uint8_t* data_; + size_t size_; + + public: + DataRange(const uint8_t* data, size_t size) : data_(data), size_(size) {} + + size_t size() const { return size_; } + + std::pair<DataRange, DataRange> split(uint32_t index) const { + return std::make_pair(DataRange(data_, index), + DataRange(data_ + index, size() - index)); + } + + std::pair<DataRange, DataRange> split() { + uint16_t index = get<uint16_t>(); + if (size() > 0) { + index = index % size(); + } else { + index = 0; + } + return split(index); + } + + template <typename T> + T get() { + if (size() == 0) { + return T(); + } else { + // We want to support the case where we have less than sizeof(T) bytes + // remaining in the slice. For example, if we emit an i32 constant, it's + // okay if we don't have a full four bytes available, we'll just use what + // we have. We aren't concerned about endianness because we are generating + // arbitrary expressions. + const size_t num_bytes = std::min(sizeof(T), size()); + T result = T(); + memcpy(&result, data_, num_bytes); + data_ += num_bytes; + size_ -= num_bytes; + return result; + } + } +}; + +class WasmGenerator { + template <WasmOpcode Op, ValueType... Args> + std::function<void(DataRange)> op() { + return [this](DataRange data) { + Generate<Args...>(data); + builder_->Emit(Op); + }; + } + + template <ValueType T> + std::function<void(DataRange)> block() { + return [this](DataRange data) { + blocks_.push_back(T); + builder_->EmitWithU8( + kExprBlock, static_cast<uint8_t>(WasmOpcodes::ValueTypeCodeFor(T))); + Generate<T>(data); + builder_->Emit(kExprEnd); + blocks_.pop_back(); + }; + } + + template <ValueType T> + std::function<void(DataRange)> block_br() { + return [this](DataRange data) { + blocks_.push_back(T); + builder_->EmitWithU8( + kExprBlock, static_cast<uint8_t>(WasmOpcodes::ValueTypeCodeFor(T))); + + const uint32_t target_block = data.get<uint32_t>() % blocks_.size(); + const ValueType break_type = blocks_[target_block]; + + Generate(break_type, data); + builder_->EmitWithVarInt(kExprBr, target_block); + builder_->Emit(kExprEnd); + blocks_.pop_back(); + }; + } + + public: + WasmGenerator(v8::internal::wasm::WasmFunctionBuilder* fn) : builder_(fn) {} + + void Generate(ValueType type, DataRange data); + + template <ValueType T> + void Generate(DataRange data); + + template <ValueType T1, ValueType T2, ValueType... Ts> + void Generate(DataRange data) { + const auto parts = data.split(); + Generate<T1>(parts.first); + Generate<T2, Ts...>(parts.second); + } + + private: + v8::internal::wasm::WasmFunctionBuilder* builder_; + std::vector<ValueType> blocks_; +}; + +template <> +void WasmGenerator::Generate<kWasmI32>(DataRange data) { + if (data.size() <= sizeof(uint32_t)) { + builder_->EmitI32Const(data.get<uint32_t>()); + } else { + const std::function<void(DataRange)> alternates[] = { + op<kExprI32Eqz, kWasmI32>(), // + op<kExprI32Eq, kWasmI32, kWasmI32>(), + op<kExprI32Ne, kWasmI32, kWasmI32>(), + op<kExprI32LtS, kWasmI32, kWasmI32>(), + op<kExprI32LtU, kWasmI32, kWasmI32>(), + op<kExprI32GeS, kWasmI32, kWasmI32>(), + op<kExprI32GeU, kWasmI32, kWasmI32>(), + + op<kExprI64Eqz, kWasmI64>(), // + op<kExprI64Eq, kWasmI64, kWasmI64>(), + op<kExprI64Ne, kWasmI64, kWasmI64>(), + op<kExprI64LtS, kWasmI64, kWasmI64>(), + op<kExprI64LtU, kWasmI64, kWasmI64>(), + op<kExprI64GeS, kWasmI64, kWasmI64>(), + op<kExprI64GeU, kWasmI64, kWasmI64>(), + + op<kExprF32Eq, kWasmF32, kWasmF32>(), + op<kExprF32Ne, kWasmF32, kWasmF32>(), + op<kExprF32Lt, kWasmF32, kWasmF32>(), + op<kExprF32Ge, kWasmF32, kWasmF32>(), + + op<kExprF64Eq, kWasmF64, kWasmF64>(), + op<kExprF64Ne, kWasmF64, kWasmF64>(), + op<kExprF64Lt, kWasmF64, kWasmF64>(), + op<kExprF64Ge, kWasmF64, kWasmF64>(), + + op<kExprI32Add, kWasmI32, kWasmI32>(), + op<kExprI32Sub, kWasmI32, kWasmI32>(), + op<kExprI32Mul, kWasmI32, kWasmI32>(), + + op<kExprI32DivS, kWasmI32, kWasmI32>(), + op<kExprI32DivU, kWasmI32, kWasmI32>(), + op<kExprI32RemS, kWasmI32, kWasmI32>(), + op<kExprI32RemU, kWasmI32, kWasmI32>(), + + op<kExprI32And, kWasmI32, kWasmI32>(), + op<kExprI32Ior, kWasmI32, kWasmI32>(), + op<kExprI32Xor, kWasmI32, kWasmI32>(), + op<kExprI32Shl, kWasmI32, kWasmI32>(), + op<kExprI32ShrU, kWasmI32, kWasmI32>(), + op<kExprI32ShrS, kWasmI32, kWasmI32>(), + op<kExprI32Ror, kWasmI32, kWasmI32>(), + op<kExprI32Rol, kWasmI32, kWasmI32>(), + + op<kExprI32Clz, kWasmI32>(), // + op<kExprI32Ctz, kWasmI32>(), // + op<kExprI32Popcnt, kWasmI32>(), + + op<kExprI32ConvertI64, kWasmI64>(), // + op<kExprI32SConvertF32, kWasmF32>(), + op<kExprI32UConvertF32, kWasmF32>(), + op<kExprI32SConvertF64, kWasmF64>(), + op<kExprI32UConvertF64, kWasmF64>(), + op<kExprI32ReinterpretF32, kWasmF32>(), + + block<kWasmI32>(), + block_br<kWasmI32>()}; + + static_assert(arraysize(alternates) < std::numeric_limits<uint8_t>::max(), + "Too many alternates. Replace with a bigger type if needed."); + const auto which = data.get<uint8_t>(); + + alternates[which % arraysize(alternates)](data); + } +} + +template <> +void WasmGenerator::Generate<kWasmI64>(DataRange data) { + if (data.size() <= sizeof(uint64_t)) { + const uint8_t bytes[] = {WASM_I64V(data.get<uint64_t>())}; + builder_->EmitCode(bytes, arraysize(bytes)); + } else { + const std::function<void(DataRange)> alternates[] = { + op<kExprI64Add, kWasmI64, kWasmI64>(), + op<kExprI64Sub, kWasmI64, kWasmI64>(), + op<kExprI64Mul, kWasmI64, kWasmI64>(), + + op<kExprI64DivS, kWasmI64, kWasmI64>(), + op<kExprI64DivU, kWasmI64, kWasmI64>(), + op<kExprI64RemS, kWasmI64, kWasmI64>(), + op<kExprI64RemU, kWasmI64, kWasmI64>(), + + op<kExprI64And, kWasmI64, kWasmI64>(), + op<kExprI64Ior, kWasmI64, kWasmI64>(), + op<kExprI64Xor, kWasmI64, kWasmI64>(), + op<kExprI64Shl, kWasmI64, kWasmI64>(), + op<kExprI64ShrU, kWasmI64, kWasmI64>(), + op<kExprI64ShrS, kWasmI64, kWasmI64>(), + op<kExprI64Ror, kWasmI64, kWasmI64>(), + op<kExprI64Rol, kWasmI64, kWasmI64>(), + + op<kExprI64Clz, kWasmI64>(), + op<kExprI64Ctz, kWasmI64>(), + op<kExprI64Popcnt, kWasmI64>(), + + block<kWasmI64>(), + block_br<kWasmI64>()}; + + static_assert(arraysize(alternates) < std::numeric_limits<uint8_t>::max(), + "Too many alternates. Replace with a bigger type if needed."); + const auto which = data.get<uint8_t>(); + + alternates[which % arraysize(alternates)](data); + } +} + +template <> +void WasmGenerator::Generate<kWasmF32>(DataRange data) { + if (data.size() <= sizeof(uint32_t)) { + const uint32_t i = data.get<uint32_t>(); + builder_->Emit(kExprF32Const); + builder_->EmitCode(reinterpret_cast<const uint8_t*>(&i), sizeof(i)); + } else { + const std::function<void(DataRange)> alternates[] = { + op<kExprF32Add, kWasmF32, kWasmF32>(), + op<kExprF32Sub, kWasmF32, kWasmF32>(), + op<kExprF32Mul, kWasmF32, kWasmF32>(), + + block<kWasmF32>(), block_br<kWasmF32>()}; + + static_assert(arraysize(alternates) < std::numeric_limits<uint8_t>::max(), + "Too many alternates. Replace with a bigger type if needed."); + const auto which = data.get<uint8_t>(); + + alternates[which % arraysize(alternates)](data); + } +} + +template <> +void WasmGenerator::Generate<kWasmF64>(DataRange data) { + if (data.size() <= sizeof(uint64_t)) { + // TODO (eholk): generate full 64-bit constants + uint64_t i = 0; + while (data.size() > 0) { + i <<= 8; + i |= data.get<uint8_t>(); + } + builder_->Emit(kExprF64Const); + builder_->EmitCode(reinterpret_cast<uint8_t*>(&i), sizeof(i)); + } else { + const std::function<void(DataRange)> alternates[] = { + op<kExprF64Add, kWasmF64, kWasmF64>(), + op<kExprF64Sub, kWasmF64, kWasmF64>(), + op<kExprF64Mul, kWasmF64, kWasmF64>(), + + block<kWasmF64>(), block_br<kWasmF64>()}; + + static_assert(arraysize(alternates) < std::numeric_limits<uint8_t>::max(), + "Too many alternates. Replace with a bigger type if needed."); + const auto which = data.get<uint8_t>(); + + alternates[which % arraysize(alternates)](data); + } +} + +void WasmGenerator::Generate(ValueType type, DataRange data) { + switch (type) { + case kWasmI32: + return Generate<kWasmI32>(data); + case kWasmI64: + return Generate<kWasmI64>(data); + case kWasmF32: + return Generate<kWasmF32>(data); + case kWasmF64: + return Generate<kWasmF64>(data); + default: + UNREACHABLE(); + } +} +} + +extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) { + // Save the flag so that we can change it and restore it later. + bool generate_test = v8::internal::FLAG_wasm_code_fuzzer_gen_test; + if (generate_test) { + v8::internal::OFStream os(stdout); + + os << "// Copyright 2017 the V8 project authors. All rights reserved." + << std::endl; + os << "// Use of this source code is governed by a BSD-style license that " + "can be" + << std::endl; + os << "// found in the LICENSE file." << std::endl; + os << std::endl; + os << "load(\"test/mjsunit/wasm/wasm-constants.js\");" << std::endl; + os << "load(\"test/mjsunit/wasm/wasm-module-builder.js\");" << std::endl; + os << std::endl; + os << "(function() {" << std::endl; + os << " var builder = new WasmModuleBuilder();" << std::endl; + os << " builder.addMemory(16, 32, false);" << std::endl; + os << " builder.addFunction(\"test\", kSig_i_iii)" << std::endl; + os << " .addBodyWithEnd([" << std::endl; + } + v8_fuzzer::FuzzerSupport* support = v8_fuzzer::FuzzerSupport::Get(); + v8::Isolate* isolate = support->GetIsolate(); + v8::internal::Isolate* i_isolate = + reinterpret_cast<v8::internal::Isolate*>(isolate); + + // Clear any pending exceptions from a prior run. + if (i_isolate->has_pending_exception()) { + i_isolate->clear_pending_exception(); + } + + v8::Isolate::Scope isolate_scope(isolate); + v8::HandleScope handle_scope(isolate); + v8::Context::Scope context_scope(support->GetContext()); + v8::TryCatch try_catch(isolate); + + v8::internal::AccountingAllocator allocator; + v8::internal::Zone zone(&allocator, ZONE_NAME); + + TestSignatures sigs; + + WasmModuleBuilder builder(&zone); + + v8::internal::wasm::WasmFunctionBuilder* f = + builder.AddFunction(sigs.i_iii()); + + WasmGenerator gen(f); + gen.Generate<kWasmI32>(DataRange(data, static_cast<uint32_t>(size))); + + uint8_t end_opcode = kExprEnd; + f->EmitCode(&end_opcode, 1); + f->ExportAs(v8::internal::CStrVector("main")); + + ZoneBuffer buffer(&zone); + builder.WriteTo(buffer); + + v8::internal::wasm::testing::SetupIsolateForWasmModule(i_isolate); + + v8::internal::HandleScope scope(i_isolate); + + ErrorThrower interpreter_thrower(i_isolate, "Interpreter"); + std::unique_ptr<const WasmModule> module(testing::DecodeWasmModuleForTesting( + i_isolate, &interpreter_thrower, buffer.begin(), buffer.end(), + v8::internal::wasm::ModuleOrigin::kWasmOrigin, true)); + + // Clear the flag so that the WebAssembly code is not printed twice. + v8::internal::FLAG_wasm_code_fuzzer_gen_test = false; + if (module == nullptr) { + if (generate_test) { + v8::internal::OFStream os(stdout); + os << " ])" << std::endl; + os << " .exportFunc();" << std::endl; + os << " assertThrows(function() { builder.instantiate(); });" + << std::endl; + os << "})();" << std::endl; + } + return 0; + } + if (generate_test) { + v8::internal::OFStream os(stdout); + os << " ])" << std::endl; + os << " .exportFunc();" << std::endl; + os << " var module = builder.instantiate();" << std::endl; + os << " module.exports.test(1, 2, 3);" << std::endl; + os << "})();" << std::endl; + } + + ModuleWireBytes wire_bytes(buffer.begin(), buffer.end()); + int32_t result_interpreted; + bool possible_nondeterminism = false; + { + WasmVal args[] = {WasmVal(1), WasmVal(2), WasmVal(3)}; + result_interpreted = testing::InterpretWasmModule( + i_isolate, &interpreter_thrower, module.get(), wire_bytes, 0, args, + &possible_nondeterminism); + } + + ErrorThrower compiler_thrower(i_isolate, "Compiler"); + v8::internal::Handle<v8::internal::JSObject> instance = + testing::InstantiateModuleForTesting(i_isolate, &compiler_thrower, + module.get(), wire_bytes); + // Restore the flag. + v8::internal::FLAG_wasm_code_fuzzer_gen_test = generate_test; + if (!interpreter_thrower.error()) { + CHECK(!instance.is_null()); + } else { + return 0; + } + int32_t result_compiled; + { + v8::internal::Handle<v8::internal::Object> arguments[] = { + v8::internal::handle(v8::internal::Smi::FromInt(1), i_isolate), + v8::internal::handle(v8::internal::Smi::FromInt(2), i_isolate), + v8::internal::handle(v8::internal::Smi::FromInt(3), i_isolate)}; + result_compiled = testing::CallWasmFunctionForTesting( + i_isolate, instance, &compiler_thrower, "main", arraysize(arguments), + arguments, v8::internal::wasm::ModuleOrigin::kWasmOrigin); + } + if (result_interpreted == bit_cast<int32_t>(0xdeadbeef) && + !possible_nondeterminism) { + CHECK(i_isolate->has_pending_exception()); + i_isolate->clear_pending_exception(); + } else { + // The WebAssembly spec allows the sign bit of NaN to be non-deterministic. + // This sign bit may cause result_interpreted to be different than + // result_compiled. Therefore we do not check the equality of the results + // if the execution may have produced a NaN at some point. + if (!possible_nondeterminism && (result_interpreted != result_compiled)) { + printf("\nInterpreter returned 0x%x but compiled code returned 0x%x\n", + result_interpreted, result_compiled); + V8_Fatal(__FILE__, __LINE__, "WasmCodeFuzzerHash=%x", + v8::internal::StringHasher::HashSequentialString( + data, static_cast<int>(size), WASM_CODE_FUZZER_HASH_SEED)); + } + } + return 0; +} diff --git a/deps/v8/test/fuzzer/wasm-data-section.cc b/deps/v8/test/fuzzer/wasm-data-section.cc index 2fbdbcd906..30b702fe8d 100644 --- a/deps/v8/test/fuzzer/wasm-data-section.cc +++ b/deps/v8/test/fuzzer/wasm-data-section.cc @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +#include "src/objects-inl.h" #include "test/fuzzer/wasm-section-fuzzers.h" extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) { diff --git a/deps/v8/test/fuzzer/wasm-function-sigs-section.cc b/deps/v8/test/fuzzer/wasm-function-sigs-section.cc index a0b66e12d0..e621aa820e 100644 --- a/deps/v8/test/fuzzer/wasm-function-sigs-section.cc +++ b/deps/v8/test/fuzzer/wasm-function-sigs-section.cc @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +#include "src/objects-inl.h" #include "test/fuzzer/wasm-section-fuzzers.h" extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) { diff --git a/deps/v8/test/fuzzer/wasm-globals-section.cc b/deps/v8/test/fuzzer/wasm-globals-section.cc index a58ef0f2b5..dccdc1079c 100644 --- a/deps/v8/test/fuzzer/wasm-globals-section.cc +++ b/deps/v8/test/fuzzer/wasm-globals-section.cc @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +#include "src/objects-inl.h" #include "test/fuzzer/wasm-section-fuzzers.h" extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) { diff --git a/deps/v8/test/fuzzer/wasm-imports-section.cc b/deps/v8/test/fuzzer/wasm-imports-section.cc index d6513e59dc..4690597bba 100644 --- a/deps/v8/test/fuzzer/wasm-imports-section.cc +++ b/deps/v8/test/fuzzer/wasm-imports-section.cc @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +#include "src/objects-inl.h" #include "test/fuzzer/wasm-section-fuzzers.h" extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) { diff --git a/deps/v8/test/fuzzer/wasm-memory-section.cc b/deps/v8/test/fuzzer/wasm-memory-section.cc index 77065f1729..4736d6e68d 100644 --- a/deps/v8/test/fuzzer/wasm-memory-section.cc +++ b/deps/v8/test/fuzzer/wasm-memory-section.cc @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +#include "src/objects-inl.h" #include "test/fuzzer/wasm-section-fuzzers.h" extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) { diff --git a/deps/v8/test/fuzzer/wasm-names-section.cc b/deps/v8/test/fuzzer/wasm-names-section.cc index 01846823ff..9a3797cf80 100644 --- a/deps/v8/test/fuzzer/wasm-names-section.cc +++ b/deps/v8/test/fuzzer/wasm-names-section.cc @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +#include "src/objects-inl.h" #include "test/fuzzer/wasm-section-fuzzers.h" extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) { diff --git a/deps/v8/test/fuzzer/wasm-section-fuzzers.cc b/deps/v8/test/fuzzer/wasm-section-fuzzers.cc index 1ef5967aa8..e98c510b77 100644 --- a/deps/v8/test/fuzzer/wasm-section-fuzzers.cc +++ b/deps/v8/test/fuzzer/wasm-section-fuzzers.cc @@ -6,6 +6,7 @@ #include "include/v8.h" #include "src/isolate.h" +#include "src/objects-inl.h" #include "src/wasm/wasm-module-builder.h" #include "src/wasm/wasm-module.h" #include "src/zone/accounting-allocator.h" diff --git a/deps/v8/test/fuzzer/wasm-section-fuzzers.h b/deps/v8/test/fuzzer/wasm-section-fuzzers.h index a28ada134e..41ff6af687 100644 --- a/deps/v8/test/fuzzer/wasm-section-fuzzers.h +++ b/deps/v8/test/fuzzer/wasm-section-fuzzers.h @@ -8,7 +8,7 @@ #include <stddef.h> #include <stdint.h> -#include "src/wasm/wasm-module.h" +#include "src/wasm/module-decoder.h" int fuzz_wasm_section(v8::internal::wasm::WasmSectionCode section, const uint8_t* data, size_t size); diff --git a/deps/v8/test/fuzzer/wasm-types-section.cc b/deps/v8/test/fuzzer/wasm-types-section.cc index 7d5fe65277..2d7e91e32a 100644 --- a/deps/v8/test/fuzzer/wasm-types-section.cc +++ b/deps/v8/test/fuzzer/wasm-types-section.cc @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +#include "src/objects-inl.h" #include "test/fuzzer/wasm-section-fuzzers.h" extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) { diff --git a/deps/v8/test/fuzzer/wasm.cc b/deps/v8/test/fuzzer/wasm.cc index 933be71344..f179450db0 100644 --- a/deps/v8/test/fuzzer/wasm.cc +++ b/deps/v8/test/fuzzer/wasm.cc @@ -17,6 +17,10 @@ #include "test/fuzzer/fuzzer-support.h" extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) { + unsigned int max_mem_flag_value = v8::internal::FLAG_wasm_max_mem_pages; + unsigned int max_table_flag_value = v8::internal::FLAG_wasm_max_table_size; + v8::internal::FLAG_wasm_max_mem_pages = 32; + v8::internal::FLAG_wasm_max_table_size = 100; v8_fuzzer::FuzzerSupport* support = v8_fuzzer::FuzzerSupport::Get(); v8::Isolate* isolate = support->GetIsolate(); v8::internal::Isolate* i_isolate = @@ -34,5 +38,7 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) { v8::internal::wasm::testing::SetupIsolateForWasmModule(i_isolate); v8::internal::wasm::testing::CompileAndRunWasmModule( i_isolate, data, data + size, v8::internal::wasm::kWasmOrigin); + v8::internal::FLAG_wasm_max_mem_pages = max_mem_flag_value; + v8::internal::FLAG_wasm_max_table_size = max_table_flag_value; return 0; } diff --git a/deps/v8/test/fuzzer/wasm_compile/foo b/deps/v8/test/fuzzer/wasm_compile/foo new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/deps/v8/test/fuzzer/wasm_compile/foo |