summaryrefslogtreecommitdiff
path: root/deps/v8/test/fuzzer
diff options
context:
space:
mode:
Diffstat (limited to 'deps/v8/test/fuzzer')
-rw-r--r--deps/v8/test/fuzzer/fuzzer-support.cc9
-rw-r--r--deps/v8/test/fuzzer/fuzzer.gyp30
-rw-r--r--deps/v8/test/fuzzer/fuzzer.isolate2
-rw-r--r--deps/v8/test/fuzzer/multi-return.cc346
-rw-r--r--deps/v8/test/fuzzer/multi_return/README.md4
-rw-r--r--deps/v8/test/fuzzer/regexp.cc2
-rw-r--r--deps/v8/test/fuzzer/testcfg.py64
-rw-r--r--deps/v8/test/fuzzer/wasm-async.cc2
-rw-r--r--deps/v8/test/fuzzer/wasm-compile.cc335
-rw-r--r--deps/v8/test/fuzzer/wasm-fuzzer-common.cc159
10 files changed, 819 insertions, 134 deletions
diff --git a/deps/v8/test/fuzzer/fuzzer-support.cc b/deps/v8/test/fuzzer/fuzzer-support.cc
index beda4899c1..d6cff118bf 100644
--- a/deps/v8/test/fuzzer/fuzzer-support.cc
+++ b/deps/v8/test/fuzzer/fuzzer-support.cc
@@ -89,7 +89,14 @@ bool FuzzerSupport::PumpMessageLoop(
} // namespace v8_fuzzer
-extern "C" int LLVMFuzzerInitialize(int* argc, char*** argv) {
+// Explicitly specify some attributes to avoid issues with the linker dead-
+// stripping the following function on macOS, as it is not called directly
+// by fuzz target. LibFuzzer runtime uses dlsym() to resolve that function.
+#if V8_OS_MACOSX
+__attribute__((used)) __attribute__((visibility("default")))
+#endif // V8_OS_MACOSX
+extern "C" int
+LLVMFuzzerInitialize(int* argc, char*** argv) {
v8_fuzzer::FuzzerSupport::InitializeFuzzerSupport(argc, argv);
return 0;
}
diff --git a/deps/v8/test/fuzzer/fuzzer.gyp b/deps/v8/test/fuzzer/fuzzer.gyp
index 3d76018d55..0c54211290 100644
--- a/deps/v8/test/fuzzer/fuzzer.gyp
+++ b/deps/v8/test/fuzzer/fuzzer.gyp
@@ -90,6 +90,36 @@
],
},
{
+ 'target_name': 'v8_simple_multi_return_fuzzer',
+ 'type': 'executable',
+ 'dependencies': [
+ 'multi_return_fuzzer_lib',
+ ],
+ 'include_dirs': [
+ '../..',
+ ],
+ 'sources': [
+ 'fuzzer.cc',
+ ],
+ },
+ {
+ 'target_name': 'multi_return_fuzzer_lib',
+ 'type': 'static_library',
+ 'dependencies': [
+ '../../src/v8.gyp:v8_libplatform',
+ 'fuzzer_support',
+ ],
+ 'include_dirs': [
+ '../..',
+ ],
+ 'sources': [ ### gcmole(all) ###
+ '../compiler/c-signature.h',
+ '../compiler/call-helper.h',
+ '../compiler/raw-machine-assembler-tester.h',
+ 'multi-return.cc',
+ ],
+ },
+ {
'target_name': 'v8_simple_wasm_fuzzer',
'type': 'executable',
'dependencies': [
diff --git a/deps/v8/test/fuzzer/fuzzer.isolate b/deps/v8/test/fuzzer/fuzzer.isolate
index 097d55885d..9391dcc7c0 100644
--- a/deps/v8/test/fuzzer/fuzzer.isolate
+++ b/deps/v8/test/fuzzer/fuzzer.isolate
@@ -8,6 +8,7 @@
'<(PRODUCT_DIR)/v8_simple_json_fuzzer<(EXECUTABLE_SUFFIX)',
'<(PRODUCT_DIR)/v8_simple_parser_fuzzer<(EXECUTABLE_SUFFIX)',
'<(PRODUCT_DIR)/v8_simple_regexp_fuzzer<(EXECUTABLE_SUFFIX)',
+ '<(PRODUCT_DIR)/v8_simple_multi_return_fuzzer<(EXECUTABLE_SUFFIX)',
'<(PRODUCT_DIR)/v8_simple_wasm_fuzzer<(EXECUTABLE_SUFFIX)',
'<(PRODUCT_DIR)/v8_simple_wasm_async_fuzzer<(EXECUTABLE_SUFFIX)',
'<(PRODUCT_DIR)/v8_simple_wasm_call_fuzzer<(EXECUTABLE_SUFFIX)',
@@ -25,6 +26,7 @@
'./json/',
'./parser/',
'./regexp/',
+ './multi_return/',
'./wasm/',
'./wasm_async/',
'./wasm_call/',
diff --git a/deps/v8/test/fuzzer/multi-return.cc b/deps/v8/test/fuzzer/multi-return.cc
new file mode 100644
index 0000000000..4766774005
--- /dev/null
+++ b/deps/v8/test/fuzzer/multi-return.cc
@@ -0,0 +1,346 @@
+// Copyright 2018 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 <cstddef>
+#include <cstdint>
+
+#include "src/compilation-info.h"
+#include "src/compiler/graph.h"
+#include "src/compiler/instruction-selector.h"
+#include "src/compiler/linkage.h"
+#include "src/compiler/node.h"
+#include "src/compiler/operator.h"
+#include "src/compiler/pipeline.h"
+#include "src/compiler/raw-machine-assembler.h"
+#include "src/machine-type.h"
+#include "src/objects-inl.h"
+#include "src/objects.h"
+#include "src/simulator.h"
+#include "src/zone/accounting-allocator.h"
+#include "src/zone/zone.h"
+#include "test/fuzzer/fuzzer-support.h"
+
+namespace v8 {
+namespace internal {
+namespace compiler {
+namespace fuzzer {
+
+constexpr MachineType kTypes[] = {
+ // The first entry is just a placeholder, because '0' is a separator.
+ MachineType(),
+#if !V8_TARGET_ARCH_32_BIT
+ MachineType::Int64(),
+#endif
+ MachineType::Int32(), MachineType::Float32(), MachineType::Float64()};
+
+static constexpr int kNumTypes = arraysize(kTypes);
+
+class InputProvider {
+ public:
+ InputProvider(const uint8_t* data, size_t size)
+ : current_(data), end_(data + size) {}
+
+ size_t NumNonZeroBytes(size_t offset, int limit) {
+ DCHECK_LE(limit, std::numeric_limits<uint8_t>::max());
+ DCHECK_GE(current_ + offset, current_);
+ const uint8_t* p;
+ for (p = current_ + offset; p < end_; ++p) {
+ if (*p % limit == 0) break;
+ }
+ return p - current_ - offset;
+ }
+
+ int NextInt8(int limit) {
+ DCHECK_LE(limit, std::numeric_limits<uint8_t>::max());
+ if (current_ == end_) return 0;
+ uint8_t result = *current_;
+ current_++;
+ return static_cast<int>(result) % limit;
+ }
+
+ int NextInt32(int limit) {
+ if (current_ + sizeof(uint32_t) > end_) return 0;
+ int result = ReadLittleEndianValue<int>(current_);
+ current_ += sizeof(uint32_t);
+ return result % limit;
+ }
+
+ private:
+ const uint8_t* current_;
+ const uint8_t* end_;
+};
+
+MachineType RandomType(InputProvider* input) {
+ return kTypes[input->NextInt8(kNumTypes)];
+}
+
+int num_registers(MachineType type) {
+ const RegisterConfiguration* config = RegisterConfiguration::Default();
+ switch (type.representation()) {
+ case MachineRepresentation::kWord32:
+ case MachineRepresentation::kWord64:
+ return config->num_allocatable_general_registers();
+ case MachineRepresentation::kFloat32:
+ return config->num_allocatable_float_registers();
+ case MachineRepresentation::kFloat64:
+ return config->num_allocatable_double_registers();
+ default:
+ UNREACHABLE();
+ }
+}
+
+int size(MachineType type) {
+ return 1 << ElementSizeLog2Of(type.representation());
+}
+
+int index(MachineType type) { return static_cast<int>(type.representation()); }
+
+const int* codes(MachineType type) {
+ const RegisterConfiguration* config = RegisterConfiguration::Default();
+ switch (type.representation()) {
+ case MachineRepresentation::kWord32:
+ case MachineRepresentation::kWord64:
+ return config->allocatable_general_codes();
+ case MachineRepresentation::kFloat32:
+ return config->allocatable_float_codes();
+ case MachineRepresentation::kFloat64:
+ return config->allocatable_double_codes();
+ default:
+ UNREACHABLE();
+ }
+}
+
+LinkageLocation AllocateLocation(MachineType type, int* int_count,
+ int* float_count, int* stack_slots) {
+ int* count = IsFloatingPoint(type.representation()) ? float_count : int_count;
+ int reg_code = *count;
+#if V8_TARGET_ARCH_ARM
+ // Allocate floats using a double register, but modify the code to
+ // reflect how ARM FP registers alias.
+ if (type == MachineType::Float32()) {
+ reg_code *= 2;
+ }
+#endif
+ LinkageLocation location = LinkageLocation::ForAnyRegister(); // Dummy.
+ if (reg_code < num_registers(type)) {
+ location = LinkageLocation::ForRegister(codes(type)[reg_code], type);
+ } else {
+ location = LinkageLocation::ForCallerFrameSlot(-*stack_slots - 1, type);
+ *stack_slots += std::max(1, size(type) / kPointerSize);
+ }
+ ++*count;
+ return location;
+}
+
+Node* Constant(RawMachineAssembler& m, MachineType type, int value) {
+ switch (type.representation()) {
+ case MachineRepresentation::kWord32:
+ return m.Int32Constant(static_cast<int32_t>(value));
+ case MachineRepresentation::kWord64:
+ return m.Int64Constant(static_cast<int64_t>(value));
+ case MachineRepresentation::kFloat32:
+ return m.Float32Constant(static_cast<float>(value));
+ case MachineRepresentation::kFloat64:
+ return m.Float64Constant(static_cast<double>(value));
+ default:
+ UNREACHABLE();
+ }
+}
+
+Node* ToInt32(RawMachineAssembler& m, MachineType type, Node* a) {
+ switch (type.representation()) {
+ case MachineRepresentation::kWord32:
+ return a;
+ case MachineRepresentation::kWord64:
+ return m.TruncateInt64ToInt32(a);
+ case MachineRepresentation::kFloat32:
+ return m.TruncateFloat32ToInt32(a);
+ case MachineRepresentation::kFloat64:
+ return m.RoundFloat64ToInt32(a);
+ default:
+ UNREACHABLE();
+ }
+}
+
+CallDescriptor* CreateRandomCallDescriptor(Zone* zone, size_t return_count,
+ size_t param_count,
+ InputProvider* input) {
+ LocationSignature::Builder locations(zone, return_count, param_count);
+
+ int stack_slots = 0;
+ int int_params = 0;
+ int float_params = 0;
+ for (size_t i = 0; i < param_count; i++) {
+ MachineType type = RandomType(input);
+ LinkageLocation location =
+ AllocateLocation(type, &int_params, &float_params, &stack_slots);
+ locations.AddParam(location);
+ }
+ // Read the end byte of the parameters.
+ input->NextInt8(1);
+
+ int stack_params = stack_slots;
+#if V8_TARGET_ARCH_ARM64
+ // Align the stack slots.
+ stack_slots = stack_slots + (stack_slots % 2);
+#endif
+ int aligned_stack_params = stack_slots;
+ int int_returns = 0;
+ int float_returns = 0;
+ for (size_t i = 0; i < return_count; i++) {
+ MachineType type = RandomType(input);
+ LinkageLocation location =
+ AllocateLocation(type, &int_returns, &float_returns, &stack_slots);
+ locations.AddReturn(location);
+ }
+ int stack_returns = stack_slots - aligned_stack_params;
+
+ MachineType target_type = MachineType::AnyTagged();
+ LinkageLocation target_loc = LinkageLocation::ForAnyRegister(target_type);
+ return new (zone) CallDescriptor( // --
+ CallDescriptor::kCallCodeObject, // kind
+ target_type, // target MachineType
+ target_loc, // target location
+ locations.Build(), // location_sig
+ stack_params, // on-stack parameter count
+ compiler::Operator::kNoProperties, // properties
+ 0, // callee-saved registers
+ 0, // callee-saved fp regs
+ CallDescriptor::kNoFlags, // flags
+ "c-call", // debug name
+ 0, // allocatable registers
+ stack_returns); // on-stack return count
+}
+
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
+ v8_fuzzer::FuzzerSupport* support = v8_fuzzer::FuzzerSupport::Get();
+ v8::Isolate* isolate = support->GetIsolate();
+ i::Isolate* i_isolate = reinterpret_cast<Isolate*>(isolate);
+ 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;
+ Zone zone(&allocator, ZONE_NAME);
+
+ InputProvider input(data, size);
+ // Create randomized descriptor.
+ size_t param_count = input.NumNonZeroBytes(0, kNumTypes);
+ size_t return_count = input.NumNonZeroBytes(param_count + 1, kNumTypes);
+ CallDescriptor* desc =
+ CreateRandomCallDescriptor(&zone, return_count, param_count, &input);
+
+ if (FLAG_wasm_fuzzer_gen_test) {
+ // Print some debugging output which describes the produced signature.
+ printf("[");
+ for (size_t j = 0; j < desc->ParameterCount(); ++j) {
+ printf(" %s",
+ MachineReprToString(desc->GetParameterType(j).representation()));
+ }
+ printf(" ] -> [");
+ for (size_t j = 0; j < desc->ReturnCount(); ++j) {
+ printf(" %s",
+ MachineReprToString(desc->GetReturnType(j).representation()));
+ }
+ printf(" ]\n\n");
+ }
+
+ // Count parameters of each type.
+ constexpr size_t kNumMachineRepresentations =
+ static_cast<size_t>(MachineRepresentation::kLastRepresentation) + 1;
+
+ // Trivial hash table for the number of occurrences of parameter types. The
+ // MachineRepresentation of the parameter types is used as hash code.
+ int counts[kNumMachineRepresentations] = {0};
+ for (size_t i = 0; i < desc->ParameterCount(); ++i) {
+ ++counts[index(desc->GetParameterType(i))];
+ }
+
+ // Generate random inputs.
+ std::unique_ptr<int[]> inputs(new int[desc->ParameterCount()]);
+ std::unique_ptr<int[]> outputs(new int[desc->ReturnCount()]);
+ for (size_t i = 0; i < desc->ParameterCount(); ++i) {
+ inputs[i] = input.NextInt32(10000);
+ }
+
+ RawMachineAssembler callee(
+ i_isolate, new (&zone) Graph(&zone), desc,
+ MachineType::PointerRepresentation(),
+ InstructionSelector::SupportedMachineOperatorFlags());
+
+ // Generate callee, returning random picks of its parameters.
+ std::unique_ptr<Node* []> params(new Node*[desc->ParameterCount() + 1]);
+ std::unique_ptr<Node* []> returns(new Node*[desc->ReturnCount()]);
+ for (size_t i = 0; i < desc->ParameterCount(); ++i) {
+ params[i] = callee.Parameter(i);
+ }
+ for (size_t i = 0; i < desc->ReturnCount(); ++i) {
+ MachineType type = desc->GetReturnType(i);
+ // Find a random same-type parameter to return. Use a constant if none.
+ if (counts[index(type)] == 0) {
+ returns[i] = Constant(callee, type, 42);
+ outputs[i] = 42;
+ } else {
+ int n = input.NextInt8(counts[index(type)]);
+ int k = 0;
+ while (desc->GetParameterType(k) != desc->GetReturnType(i) || --n > 0) {
+ ++k;
+ }
+ returns[i] = params[k];
+ outputs[i] = inputs[k];
+ }
+ }
+ callee.Return(static_cast<int>(desc->ReturnCount()), returns.get());
+
+ CompilationInfo info(ArrayVector("testing"), &zone, Code::STUB);
+ Handle<Code> code = Pipeline::GenerateCodeForTesting(
+ &info, i_isolate, desc, callee.graph(), callee.Export());
+
+ // Generate wrapper.
+ int expect = 0;
+
+ MachineSignature::Builder sig_builder(&zone, 1, 0);
+ sig_builder.AddReturn(MachineType::Int32());
+
+ CallDescriptor* wrapper_desc =
+ Linkage::GetSimplifiedCDescriptor(&zone, sig_builder.Build());
+ RawMachineAssembler caller(
+ i_isolate, new (&zone) Graph(&zone), wrapper_desc,
+ MachineType::PointerRepresentation(),
+ InstructionSelector::SupportedMachineOperatorFlags());
+
+ params[0] = caller.HeapConstant(code);
+ for (size_t i = 0; i < desc->ParameterCount(); ++i) {
+ params[i + 1] = Constant(caller, desc->GetParameterType(i), inputs[i]);
+ }
+ Node* call = caller.AddNode(caller.common()->Call(desc),
+ static_cast<int>(desc->ParameterCount() + 1),
+ params.get());
+ Node* ret = Constant(caller, MachineType::Int32(), 0);
+ for (size_t i = 0; i < desc->ReturnCount(); ++i) {
+ // Skip roughly one third of the outputs.
+ if (input.NextInt8(3) == 0) continue;
+ Node* ret_i = (desc->ReturnCount() == 1)
+ ? call
+ : caller.AddNode(caller.common()->Projection(i), call);
+ ret = caller.Int32Add(ret, ToInt32(caller, desc->GetReturnType(i), ret_i));
+ expect += outputs[i];
+ }
+ caller.Return(ret);
+
+ // Call the wrapper.
+ CompilationInfo wrapper_info(ArrayVector("wrapper"), &zone, Code::STUB);
+ Handle<Code> wrapper_code = Pipeline::GenerateCodeForTesting(
+ &wrapper_info, i_isolate, wrapper_desc, caller.graph(), caller.Export());
+ auto fn = GeneratedCode<int32_t>::FromCode(*wrapper_code);
+ int result = fn.Call();
+
+ CHECK_EQ(expect, result);
+ return 0;
+}
+
+} // namespace fuzzer
+} // namespace compiler
+} // namespace internal
+} // namespace v8
diff --git a/deps/v8/test/fuzzer/multi_return/README.md b/deps/v8/test/fuzzer/multi_return/README.md
new file mode 100644
index 0000000000..a3764e8a7c
--- /dev/null
+++ b/deps/v8/test/fuzzer/multi_return/README.md
@@ -0,0 +1,4 @@
+All files in this directory are used by the trybots to check that the fuzzer
+executes correctly, see
+https://github.com/v8/v8/blob/master/test/fuzzer/README.md. There should be at
+least one file in this directory, e.g. this README file.
diff --git a/deps/v8/test/fuzzer/regexp.cc b/deps/v8/test/fuzzer/regexp.cc
index c73901b0e0..b652bd7e3f 100644
--- a/deps/v8/test/fuzzer/regexp.cc
+++ b/deps/v8/test/fuzzer/regexp.cc
@@ -49,7 +49,7 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
static const int kAllFlags = i::JSRegExp::kGlobal | i::JSRegExp::kIgnoreCase |
i::JSRegExp::kMultiline | i::JSRegExp::kSticky |
- i::JSRegExp::kUnicode;
+ i::JSRegExp::kUnicode | i::JSRegExp::kDotAll;
const uint8_t one_byte_array[6] = {'f', 'o', 'o', 'b', 'a', 'r'};
const i::uc16 two_byte_array[6] = {'f', 0xD83D, 0xDCA9, 'b', 'a', 0x2603};
diff --git a/deps/v8/test/fuzzer/testcfg.py b/deps/v8/test/fuzzer/testcfg.py
index 17cb0ef588..b3fe174d95 100644
--- a/deps/v8/test/fuzzer/testcfg.py
+++ b/deps/v8/test/fuzzer/testcfg.py
@@ -8,47 +8,57 @@ from testrunner.local import testsuite
from testrunner.objects import testcase
-class FuzzerVariantGenerator(testsuite.VariantGenerator):
- # Only run the fuzzer with standard variant.
- def FilterVariantsByTest(self, testcase):
- return self.standard_variant
+class VariantsGenerator(testsuite.VariantsGenerator):
+ def _get_variants(self, test):
+ return self._standard_variant
- def GetFlagSets(self, testcase, variant):
- return testsuite.FAST_VARIANT_FLAGS[variant]
-
-class FuzzerTestSuite(testsuite.TestSuite):
- SUB_TESTS = ( 'json', 'parser', 'regexp', 'wasm', 'wasm_async',
- 'wasm_call', '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)
+class TestSuite(testsuite.TestSuite):
+ SUB_TESTS = ( 'json', 'parser', 'regexp', 'multi_return', 'wasm',
+ 'wasm_async', 'wasm_call', '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 ListTests(self, context):
tests = []
- for subtest in FuzzerTestSuite.SUB_TESTS:
+ for subtest in TestSuite.SUB_TESTS:
for fname in os.listdir(os.path.join(self.root, subtest)):
if not os.path.isfile(os.path.join(self.root, subtest, fname)):
continue
- test = testcase.TestCase(self, '%s/%s' % (subtest, fname))
+ test = self._create_test('%s/%s' % (subtest, fname))
tests.append(test)
tests.sort()
return tests
- def GetShellForTestCase(self, testcase):
- group, _ = testcase.path.split('/', 1)
- return 'v8_simple_%s_fuzzer' % group
+ def _test_class(self):
+ return TestCase
+
+ def _variants_gen_class(self):
+ return VariantsGenerator
+
+ def _LegacyVariantsGeneratorFactory(self):
+ return testsuite.StandardLegacyVariantsGenerator
- def GetParametersForTestCase(self, testcase, context):
- suite, name = testcase.path.split('/')
- return [os.path.join(self.root, suite, name)], [], {}
- def _VariantGeneratorFactory(self):
- return FuzzerVariantGenerator
+class TestCase(testcase.TestCase):
+ def _get_files_params(self, ctx):
+ suite, name = self.path.split('/')
+ return [os.path.join(self.suite.root, suite, name)]
+
+ def _get_variant_flags(self):
+ return []
+
+ def _get_statusfile_flags(self):
+ return []
+
+ def _get_mode_flags(self, ctx):
+ return []
+
+ def get_shell(self):
+ group, _ = self.path.split('/', 1)
+ return 'v8_simple_%s_fuzzer' % group
def GetSuite(name, root):
- return FuzzerTestSuite(name, root)
+ return TestSuite(name, root)
diff --git a/deps/v8/test/fuzzer/wasm-async.cc b/deps/v8/test/fuzzer/wasm-async.cc
index 13b15a9d70..4718601b0f 100644
--- a/deps/v8/test/fuzzer/wasm-async.cc
+++ b/deps/v8/test/fuzzer/wasm-async.cc
@@ -94,7 +94,7 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
Local<Promise> promise = resolver->GetPromise();
AsyncCompile(i_isolate, Utils::OpenHandle(*promise),
- ModuleWireBytes(data, data + size));
+ ModuleWireBytes(data, data + size), false);
ASSIGN(Function, instantiate_impl,
Function::New(support->GetContext(), &InstantiateCallback,
diff --git a/deps/v8/test/fuzzer/wasm-compile.cc b/deps/v8/test/fuzzer/wasm-compile.cc
index ded3a101f2..4192a938e8 100644
--- a/deps/v8/test/fuzzer/wasm-compile.cc
+++ b/deps/v8/test/fuzzer/wasm-compile.cc
@@ -30,6 +30,8 @@ namespace fuzzer {
namespace {
+constexpr int kMaxFunctions = 4;
+
class DataRange {
const uint8_t* data_;
size_t size_;
@@ -37,46 +39,67 @@ class DataRange {
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));
+ // Don't accidentally pass DataRange by value. This will reuse bytes and might
+ // lead to OOM because the end might not be reached.
+ // Define move constructor and move assignment, disallow copy constructor and
+ // copy assignment (below).
+ DataRange(DataRange&& other) : DataRange(other.data_, other.size_) {
+ other.data_ = nullptr;
+ other.size_ = 0;
+ }
+ DataRange& operator=(DataRange&& other) {
+ data_ = other.data_;
+ size_ = other.size_;
+ other.data_ = nullptr;
+ other.size_ = 0;
+ return *this;
}
- std::pair<DataRange, DataRange> split() {
- uint16_t index = get<uint16_t>();
- if (size() > 0) {
- index = index % size();
- } else {
- index = 0;
- }
- return split(index);
+ size_t size() const { return size_; }
+
+ DataRange split() {
+ uint16_t num_bytes = get<uint16_t>() % std::max(size_t{1}, size_);
+ DataRange split(data_, num_bytes);
+ data_ += num_bytes;
+ size_ -= num_bytes;
+ return split;
}
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;
- }
+ // 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;
}
+
+ DISALLOW_COPY_AND_ASSIGN(DataRange);
};
+ValueType GetValueType(DataRange& data) {
+ switch (data.get<uint8_t>() % 4) {
+ case 0:
+ return kWasmI32;
+ case 1:
+ return kWasmI64;
+ case 2:
+ return kWasmF32;
+ case 3:
+ return kWasmF64;
+ }
+ UNREACHABLE();
+}
+
class WasmGenerator {
template <WasmOpcode Op, ValueType... Args>
- void op(DataRange data) {
+ void op(DataRange& data) {
Generate<Args...>(data);
builder_->Emit(Op);
}
@@ -101,20 +124,20 @@ class WasmGenerator {
};
template <ValueType T>
- void block(DataRange data) {
+ void block(DataRange& data) {
BlockScope block_scope(this, kExprBlock, T, T);
Generate<T>(data);
}
template <ValueType T>
- void loop(DataRange data) {
+ void loop(DataRange& data) {
// When breaking to a loop header, don't provide any input value (hence
// kWasmStmt).
BlockScope block_scope(this, kExprLoop, T, kWasmStmt);
Generate<T>(data);
}
- void br(DataRange data) {
+ void br(DataRange& data) {
// There is always at least the block representing the function body.
DCHECK(!blocks_.empty());
const uint32_t target_block = data.get<uint32_t>() % blocks_.size();
@@ -161,7 +184,7 @@ class WasmGenerator {
}
template <WasmOpcode memory_op, ValueType... arg_types>
- void memop(DataRange data) {
+ void memop(DataRange& data) {
const uint8_t align = data.get<uint8_t>() % (max_alignment(memory_op) + 1);
const uint32_t offset = data.get<uint32_t>();
@@ -173,21 +196,131 @@ class WasmGenerator {
builder_->EmitU32V(offset);
}
+ void drop(DataRange& data) {
+ Generate(GetValueType(data), data);
+ builder_->Emit(kExprDrop);
+ }
+
+ template <ValueType wanted_type>
+ void call(DataRange& data) {
+ call(data, wanted_type);
+ }
+
+ void Convert(ValueType src, ValueType dst) {
+ auto idx = [](ValueType t) -> int {
+ switch (t) {
+ case kWasmI32:
+ return 0;
+ case kWasmI64:
+ return 1;
+ case kWasmF32:
+ return 2;
+ case kWasmF64:
+ return 3;
+ default:
+ UNREACHABLE();
+ }
+ };
+ static constexpr WasmOpcode kConvertOpcodes[] = {
+ // {i32, i64, f32, f64} -> i32
+ kExprNop, kExprI32ConvertI64, kExprI32SConvertF32, kExprI32SConvertF64,
+ // {i32, i64, f32, f64} -> i64
+ kExprI64SConvertI32, kExprNop, kExprI64SConvertF32, kExprI64SConvertF64,
+ // {i32, i64, f32, f64} -> f32
+ kExprF32SConvertI32, kExprF32SConvertI64, kExprNop, kExprF32ConvertF64,
+ // {i32, i64, f32, f64} -> f64
+ kExprF64SConvertI32, kExprF64SConvertI64, kExprF64ConvertF32, kExprNop};
+ int arr_idx = idx(dst) << 2 | idx(src);
+ builder_->Emit(kConvertOpcodes[arr_idx]);
+ }
+
+ void call(DataRange& data, ValueType wanted_type) {
+ int func_index = data.get<uint8_t>() % functions_.size();
+ FunctionSig* sig = functions_[func_index];
+ // Generate arguments.
+ for (size_t i = 0; i < sig->parameter_count(); ++i) {
+ Generate(sig->GetParam(i), data);
+ }
+ // Emit call.
+ builder_->EmitWithU32V(kExprCallFunction, func_index);
+ // Convert the return value to the wanted type.
+ ValueType return_type =
+ sig->return_count() == 0 ? kWasmStmt : sig->GetReturn(0);
+ if (return_type == kWasmStmt && wanted_type != kWasmStmt) {
+ // The call did not generate a value. Thus just generate it here.
+ Generate(wanted_type, data);
+ } else if (return_type != kWasmStmt && wanted_type == kWasmStmt) {
+ // The call did generate a value, but we did not want one.
+ builder_->Emit(kExprDrop);
+ } else if (return_type != wanted_type) {
+ // If the returned type does not match the wanted type, convert it.
+ Convert(return_type, wanted_type);
+ }
+ }
+
+ struct Local {
+ uint32_t index;
+ ValueType type = kWasmStmt;
+ Local() = default;
+ Local(uint32_t index, ValueType type) : index(index), type(type) {}
+ bool is_valid() const { return type != kWasmStmt; }
+ };
+
+ Local GetRandomLocal(DataRange& data) {
+ uint32_t num_params =
+ static_cast<uint32_t>(builder_->signature()->parameter_count());
+ uint32_t num_locals = static_cast<uint32_t>(locals_.size());
+ if (num_params + num_locals == 0) return {};
+ uint32_t index = data.get<uint8_t>() % (num_params + num_locals);
+ ValueType type = index < num_params ? builder_->signature()->GetParam(index)
+ : locals_[index - num_params];
+ return {index, type};
+ }
+
+ template <ValueType wanted_type>
+ void local_op(DataRange& data, WasmOpcode opcode) {
+ Local local = GetRandomLocal(data);
+ // If there are no locals and no parameters, just generate any value (if a
+ // value is needed), or do nothing.
+ if (!local.is_valid()) {
+ if (wanted_type == kWasmStmt) return;
+ return Generate<wanted_type>(data);
+ }
+
+ if (opcode != kExprGetLocal) Generate(local.type, data);
+ builder_->EmitWithU32V(opcode, local.index);
+ if (wanted_type != kWasmStmt && local.type != wanted_type) {
+ Convert(local.type, wanted_type);
+ }
+ }
+
+ template <ValueType wanted_type>
+ void get_local(DataRange& data) {
+ local_op<wanted_type>(data, kExprGetLocal);
+ }
+
+ void set_local(DataRange& data) { local_op<kWasmStmt>(data, kExprSetLocal); }
+
+ template <ValueType wanted_type>
+ void tee_local(DataRange& data) {
+ local_op<wanted_type>(data, kExprTeeLocal);
+ }
+
template <ValueType T1, ValueType T2>
- void sequence(DataRange data) {
+ void sequence(DataRange& data) {
Generate<T1, T2>(data);
}
- void current_memory(DataRange data) {
+ void current_memory(DataRange& data) {
builder_->EmitWithU8(kExprMemorySize, 0);
}
- void grow_memory(DataRange data);
+ void grow_memory(DataRange& data);
- using generate_fn = void (WasmGenerator::*const)(DataRange);
+ using generate_fn = void (WasmGenerator::*const)(DataRange&);
template <size_t N>
- void GenerateOneOf(generate_fn (&alternates)[N], DataRange data) {
+ void GenerateOneOf(generate_fn (&alternates)[N], DataRange& data) {
static_assert(N < std::numeric_limits<uint8_t>::max(),
"Too many alternates. Replace with a bigger type if needed.");
const auto which = data.get<uint8_t>();
@@ -209,26 +342,39 @@ class WasmGenerator {
};
public:
- explicit WasmGenerator(WasmFunctionBuilder* fn) : builder_(fn) {
- DCHECK_EQ(1, fn->signature()->return_count());
- blocks_.push_back(fn->signature()->GetReturn(0));
+ WasmGenerator(WasmFunctionBuilder* fn,
+ const std::vector<FunctionSig*>& functions, DataRange& data)
+ : builder_(fn), functions_(functions) {
+ FunctionSig* sig = fn->signature();
+ DCHECK_GE(1, sig->return_count());
+ blocks_.push_back(sig->return_count() == 0 ? kWasmStmt : sig->GetReturn(0));
+
+ constexpr uint32_t kMaxLocals = 32;
+ locals_.resize(data.get<uint8_t>() % kMaxLocals);
+ for (ValueType& local : locals_) {
+ local = GetValueType(data);
+ fn->AddLocal(local);
+ }
}
- void Generate(ValueType type, DataRange data);
+ void Generate(ValueType type, DataRange& data);
template <ValueType T>
- void Generate(DataRange data);
+ 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);
+ void Generate(DataRange& data) {
+ // TODO(clemensh): Implement a more even split.
+ auto first_data = data.split();
+ Generate<T1>(first_data);
+ Generate<T2, Ts...>(data);
}
private:
WasmFunctionBuilder* builder_;
std::vector<ValueType> blocks_;
+ const std::vector<FunctionSig*>& functions_;
+ std::vector<ValueType> locals_;
uint32_t recursion_depth = 0;
static constexpr uint32_t kMaxRecursionDepth = 64;
@@ -239,7 +385,7 @@ class WasmGenerator {
};
template <>
-void WasmGenerator::Generate<kWasmStmt>(DataRange data) {
+void WasmGenerator::Generate<kWasmStmt>(DataRange& data) {
GeneratorRecursionScope rec_scope(this);
if (recursion_limit_reached() || data.size() == 0) return;
@@ -257,13 +403,18 @@ void WasmGenerator::Generate<kWasmStmt>(DataRange data) {
&WasmGenerator::memop<kExprI64StoreMem32, kWasmI64>,
&WasmGenerator::memop<kExprF32StoreMem, kWasmF32>,
&WasmGenerator::memop<kExprF64StoreMem, kWasmF64>,
- };
+
+ &WasmGenerator::drop,
+
+ &WasmGenerator::call<kWasmStmt>,
+
+ &WasmGenerator::set_local};
GenerateOneOf(alternates, data);
}
template <>
-void WasmGenerator::Generate<kWasmI32>(DataRange data) {
+void WasmGenerator::Generate<kWasmI32>(DataRange& data) {
GeneratorRecursionScope rec_scope(this);
if (recursion_limit_reached() || data.size() <= sizeof(uint32_t)) {
builder_->EmitI32Const(data.get<uint32_t>());
@@ -338,13 +489,18 @@ void WasmGenerator::Generate<kWasmI32>(DataRange data) {
&WasmGenerator::memop<kExprI32LoadMem16U>,
&WasmGenerator::current_memory,
- &WasmGenerator::grow_memory};
+ &WasmGenerator::grow_memory,
+
+ &WasmGenerator::get_local<kWasmI32>,
+ &WasmGenerator::tee_local<kWasmI32>,
+
+ &WasmGenerator::call<kWasmI32>};
GenerateOneOf(alternates, data);
}
template <>
-void WasmGenerator::Generate<kWasmI64>(DataRange data) {
+void WasmGenerator::Generate<kWasmI64>(DataRange& data) {
GeneratorRecursionScope rec_scope(this);
if (recursion_limit_reached() || data.size() <= sizeof(uint64_t)) {
builder_->EmitI64Const(data.get<int64_t>());
@@ -385,13 +541,18 @@ void WasmGenerator::Generate<kWasmI64>(DataRange data) {
&WasmGenerator::memop<kExprI64LoadMem16S>,
&WasmGenerator::memop<kExprI64LoadMem16U>,
&WasmGenerator::memop<kExprI64LoadMem32S>,
- &WasmGenerator::memop<kExprI64LoadMem32U>};
+ &WasmGenerator::memop<kExprI64LoadMem32U>,
+
+ &WasmGenerator::get_local<kWasmI64>,
+ &WasmGenerator::tee_local<kWasmI64>,
+
+ &WasmGenerator::call<kWasmI64>};
GenerateOneOf(alternates, data);
}
template <>
-void WasmGenerator::Generate<kWasmF32>(DataRange data) {
+void WasmGenerator::Generate<kWasmF32>(DataRange& data) {
GeneratorRecursionScope rec_scope(this);
if (recursion_limit_reached() || data.size() <= sizeof(float)) {
builder_->EmitF32Const(data.get<float>());
@@ -408,13 +569,18 @@ void WasmGenerator::Generate<kWasmF32>(DataRange data) {
&WasmGenerator::block<kWasmF32>,
&WasmGenerator::loop<kWasmF32>,
- &WasmGenerator::memop<kExprF32LoadMem>};
+ &WasmGenerator::memop<kExprF32LoadMem>,
+
+ &WasmGenerator::get_local<kWasmF32>,
+ &WasmGenerator::tee_local<kWasmF32>,
+
+ &WasmGenerator::call<kWasmF32>};
GenerateOneOf(alternates, data);
}
template <>
-void WasmGenerator::Generate<kWasmF64>(DataRange data) {
+void WasmGenerator::Generate<kWasmF64>(DataRange& data) {
GeneratorRecursionScope rec_scope(this);
if (recursion_limit_reached() || data.size() <= sizeof(double)) {
builder_->EmitF64Const(data.get<double>());
@@ -431,17 +597,22 @@ void WasmGenerator::Generate<kWasmF64>(DataRange data) {
&WasmGenerator::block<kWasmF64>,
&WasmGenerator::loop<kWasmF64>,
- &WasmGenerator::memop<kExprF64LoadMem>};
+ &WasmGenerator::memop<kExprF64LoadMem>,
+
+ &WasmGenerator::get_local<kWasmF64>,
+ &WasmGenerator::tee_local<kWasmF64>,
+
+ &WasmGenerator::call<kWasmF64>};
GenerateOneOf(alternates, data);
}
-void WasmGenerator::grow_memory(DataRange data) {
+void WasmGenerator::grow_memory(DataRange& data) {
Generate<kWasmI32>(data);
builder_->EmitWithU8(kExprGrowMemory, 0);
}
-void WasmGenerator::Generate(ValueType type, DataRange data) {
+void WasmGenerator::Generate(ValueType type, DataRange& data) {
switch (type) {
case kWasmStmt:
return Generate<kWasmStmt>(data);
@@ -457,6 +628,19 @@ void WasmGenerator::Generate(ValueType type, DataRange data) {
UNREACHABLE();
}
}
+
+FunctionSig* GenerateSig(Zone* zone, DataRange& data) {
+ // Generate enough parameters to spill some to the stack.
+ constexpr int kMaxParameters = 15;
+ int num_params = int{data.get<uint8_t>()} % (kMaxParameters + 1);
+ bool has_return = data.get<bool>();
+
+ FunctionSig::Builder builder(zone, has_return ? 1 : 0, num_params);
+ if (has_return) builder.AddReturn(GetValueType(data));
+ for (int i = 0; i < num_params; ++i) builder.AddParam(GetValueType(data));
+ return builder.Build();
+}
+
} // namespace
class WasmCompileFuzzer : public WasmExecutionFuzzer {
@@ -469,13 +653,32 @@ class WasmCompileFuzzer : public WasmExecutionFuzzer {
WasmModuleBuilder builder(zone);
- WasmFunctionBuilder* f = builder.AddFunction(sigs.i_iii());
+ DataRange range(data, static_cast<uint32_t>(size));
+ std::vector<FunctionSig*> function_signatures;
+ function_signatures.push_back(sigs.i_iii());
+
+ static_assert(kMaxFunctions >= 1, "need min. 1 function");
+ int num_functions = 1 + (range.get<uint8_t>() % kMaxFunctions);
+
+ for (int i = 1; i < num_functions; ++i) {
+ function_signatures.push_back(GenerateSig(zone, range));
+ }
- WasmGenerator gen(f);
- gen.Generate<kWasmI32>(DataRange(data, static_cast<uint32_t>(size)));
+ for (int i = 0; i < num_functions; ++i) {
+ DataRange function_range =
+ i == num_functions - 1 ? std::move(range) : range.split();
- f->Emit(kExprEnd);
- builder.AddExport(CStrVector("main"), f);
+ FunctionSig* sig = function_signatures[i];
+ WasmFunctionBuilder* f = builder.AddFunction(sig);
+
+ WasmGenerator gen(f, function_signatures, function_range);
+ ValueType return_type =
+ sig->return_count() == 0 ? kWasmStmt : sig->GetReturn(0);
+ gen.Generate(return_type, function_range);
+
+ f->Emit(kExprEnd);
+ if (i == 0) builder.AddExport(CStrVector("main"), f);
+ }
builder.SetMaxMemorySize(32);
builder.WriteTo(buffer);
@@ -485,8 +688,8 @@ class WasmCompileFuzzer : public WasmExecutionFuzzer {
new WasmValue[3]{WasmValue(1), WasmValue(2), WasmValue(3)});
compiler_args.reset(new Handle<Object>[3]{
- handle(Smi::FromInt(1), isolate), handle(Smi::FromInt(1), isolate),
- handle(Smi::FromInt(1), isolate)});
+ handle(Smi::FromInt(1), isolate), handle(Smi::FromInt(2), isolate),
+ handle(Smi::FromInt(3), isolate)});
return true;
}
};
diff --git a/deps/v8/test/fuzzer/wasm-fuzzer-common.cc b/deps/v8/test/fuzzer/wasm-fuzzer-common.cc
index 4e6aed1a25..46f5133486 100644
--- a/deps/v8/test/fuzzer/wasm-fuzzer-common.cc
+++ b/deps/v8/test/fuzzer/wasm-fuzzer-common.cc
@@ -9,6 +9,7 @@
#include "src/objects-inl.h"
#include "src/wasm/module-compiler.h"
#include "src/wasm/wasm-api.h"
+#include "src/wasm/wasm-engine.h"
#include "src/wasm/wasm-module-builder.h"
#include "src/wasm/wasm-module.h"
#include "src/zone/accounting-allocator.h"
@@ -89,29 +90,123 @@ void InterpretAndExecuteModule(i::Isolate* isolate,
testing::RunWasmModuleForTesting(isolate, instance, 0, nullptr);
}
+namespace {
+struct PrintSig {
+ const size_t num;
+ const std::function<ValueType(size_t)> getter;
+};
+PrintSig PrintParameters(const FunctionSig* sig) {
+ return {sig->parameter_count(), [=](size_t i) { return sig->GetParam(i); }};
+}
+PrintSig PrintReturns(const FunctionSig* sig) {
+ return {sig->return_count(), [=](size_t i) { return sig->GetReturn(i); }};
+}
+const char* ValueTypeToConstantName(ValueType type) {
+ switch (type) {
+ case kWasmI32:
+ return "kWasmI32";
+ case kWasmI64:
+ return "kWasmI64";
+ case kWasmF32:
+ return "kWasmF32";
+ case kWasmF64:
+ return "kWasmF64";
+ default:
+ UNREACHABLE();
+ }
+}
+std::ostream& operator<<(std::ostream& os, const PrintSig& print) {
+ os << "[";
+ for (size_t i = 0; i < print.num; ++i) {
+ os << (i == 0 ? "" : ", ") << ValueTypeToConstantName(print.getter(i));
+ }
+ return os << "]";
+}
+
+void GenerateTestCase(Isolate* isolate, ModuleWireBytes wire_bytes,
+ bool compiles) {
+ constexpr bool kVerifyFunctions = false;
+ ModuleResult module_res =
+ SyncDecodeWasmModule(isolate, wire_bytes.start(), wire_bytes.end(),
+ kVerifyFunctions, ModuleOrigin::kWasmOrigin);
+ CHECK(module_res.ok());
+ WasmModule* module = module_res.val.get();
+ CHECK_NOT_NULL(module);
+
+ OFStream os(stdout);
+
+ os << "// Copyright 2018 the V8 project authors. All rights reserved.\n"
+ "// Use of this source code is governed by a BSD-style license that "
+ "can be\n"
+ "// found in the LICENSE file.\n"
+ "\n"
+ "load('test/mjsunit/wasm/wasm-constants.js');\n"
+ "load('test/mjsunit/wasm/wasm-module-builder.js');\n"
+ "\n"
+ "(function() {\n"
+ " var builder = new WasmModuleBuilder();\n";
+
+ if (module->has_memory) {
+ os << " builder.addMemory(" << module->initial_pages;
+ if (module->has_maximum_pages) {
+ os << ", " << module->maximum_pages << ");\n";
+ } else {
+ os << ");\n";
+ }
+ }
+
+ Zone tmp_zone(isolate->allocator(), ZONE_NAME);
+
+ for (const WasmFunction& func : module->functions) {
+ Vector<const uint8_t> func_code = wire_bytes.GetFunctionBytes(&func);
+ os << " // Generate function " << func.func_index + 1 << " of "
+ << module->functions.size() << ".\n";
+ // Generate signature.
+ os << " sig" << func.func_index << " = makeSig("
+ << PrintParameters(func.sig) << ", " << PrintReturns(func.sig) << ");\n";
+
+ // Add function.
+ os << " builder.addFunction(undefined, sig" << func.func_index << ")\n";
+
+ // Add locals.
+ BodyLocalDecls decls(&tmp_zone);
+ DecodeLocalDecls(&decls, func_code.start(), func_code.end());
+ if (!decls.type_list.empty()) {
+ os << " ";
+ for (size_t pos = 0, count = 1, locals = decls.type_list.size();
+ pos < locals; pos += count, count = 1) {
+ ValueType type = decls.type_list[pos];
+ while (pos + count < locals && decls.type_list[pos + count] == type)
+ ++count;
+ os << ".addLocals({" << WasmOpcodes::TypeName(type)
+ << "_count: " << count << "})";
+ }
+ os << "\n";
+ }
+
+ // Add body.
+ os << " .addBodyWithEnd([\n";
+
+ FunctionBody func_body(func.sig, func.code.offset(), func_code.start(),
+ func_code.end());
+ PrintRawWasmCode(isolate->allocator(), func_body, module, kOmitLocals);
+ os << " ])";
+ if (func.func_index == 0) os << "\n .exportAs('main')";
+ os << ";\n ";
+ }
+
+ if (compiles) {
+ os << " var module = builder.instantiate();\n"
+ " module.exports.main(1, 2, 3);\n";
+ } else {
+ os << " assertThrows(function() { builder.instantiate(); });\n";
+ }
+ os << "})();\n";
+}
+} // namespace
+
int WasmExecutionFuzzer::FuzzWasmModule(const uint8_t* data, size_t size,
bool require_valid) {
- // Save the flag so that we can change it and restore it later.
- bool generate_test = FLAG_wasm_code_fuzzer_gen_test;
- if (generate_test) {
- 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();
i::Isolate* i_isolate = reinterpret_cast<Isolate*>(isolate);
@@ -148,26 +243,14 @@ int WasmExecutionFuzzer::FuzzWasmModule(const uint8_t* data, size_t size,
FlagScope<bool> no_liftoff(&FLAG_liftoff, false);
compiled_module = SyncCompile(i_isolate, &interpreter_thrower, wire_bytes);
}
- // Clear the flag so that the WebAssembly code is not printed twice.
- FLAG_wasm_code_fuzzer_gen_test = false;
bool compiles = !compiled_module.is_null();
- if (generate_test) {
- OFStream os(stdout);
- os << " ])" << std::endl
- << " .exportFunc();" << std::endl;
- if (compiles) {
- os << " var module = builder.instantiate();" << std::endl
- << " module.exports.test(1, 2, 3);" << std::endl;
- } else {
- OFStream os(stdout);
- os << " assertThrows(function() { builder.instantiate(); });"
- << std::endl;
- }
- os << "})();" << std::endl;
+ if (FLAG_wasm_fuzzer_gen_test) {
+ GenerateTestCase(i_isolate, wire_bytes, compiles);
}
- bool validates = SyncValidate(i_isolate, wire_bytes);
+ bool validates =
+ i_isolate->wasm_engine()->SyncValidate(i_isolate, wire_bytes);
CHECK_EQ(compiles, validates);
CHECK_IMPLIES(require_valid, validates);
@@ -198,7 +281,7 @@ int WasmExecutionFuzzer::FuzzWasmModule(const uint8_t* data, size_t size,
}
bool expect_exception =
- result_interpreter == static_cast<int32_t>(0xdeadbeef);
+ result_interpreter == static_cast<int32_t>(0xDEADBEEF);
int32_t result_turbofan;
{