Commit 3bacf755 authored by Clemens Hammacher's avatar Clemens Hammacher Committed by Commit Bot

[wasm][fuzzer] Refactor and fix test case generation

Test case generation produced unusable output if the module contains
more than one function. Also, it was unnecessarily scattered around
several places in the code.
This CL consolidates test case generation in one method in the fuzzer,
and supports multiple functions with different signatures.

R=ahaas@chromium.org

Change-Id: I8bea71b0d69bb69d8bbe50002c6c7616a0a1941b
Reviewed-on: https://chromium-review.googlesource.com/847515
Commit-Queue: Clemens Hammacher <clemensh@chromium.org>
Reviewed-by: 's avatarAndreas Haas <ahaas@chromium.org>
Cr-Commit-Position: refs/heads/master@{#50400}
parent da3416f5
......@@ -4891,7 +4891,8 @@ SourcePositionTable* WasmCompilationUnit::BuildGraphForWasmFunction(
if (func_index_ >= FLAG_trace_wasm_ast_start &&
func_index_ < FLAG_trace_wasm_ast_end) {
PrintRawWasmCode(isolate_->allocator(), func_body_, env_->module);
PrintRawWasmCode(isolate_->allocator(), func_body_, env_->module,
wasm::kPrintLocals);
}
if (FLAG_trace_wasm_decode_time) {
*decode_ms = decode_timer.Elapsed().InMillisecondsF();
......
......@@ -567,8 +567,9 @@ DEFINE_BOOL(wasm_no_stack_checks, false,
DEFINE_BOOL(wasm_trap_handler, false,
"use signal handlers to catch out of bounds memory access in wasm"
" (experimental, currently Linux x86_64 only)")
DEFINE_BOOL(wasm_code_fuzzer_gen_test, false,
"Generate a test case when running the wasm-code fuzzer")
DEFINE_BOOL(wasm_fuzzer_gen_test, false,
"Generate a test case when running a wasm fuzzer")
DEFINE_IMPLICATION(wasm_fuzzer_gen_test, single_threaded)
DEFINE_BOOL(print_wasm_code, false, "Print WebAssembly code")
DEFINE_BOOL(wasm_interpret_all, false,
"Execute all wasm code in the wasm interpreter")
......
......@@ -1156,9 +1156,6 @@ class WasmFullDecoder : public WasmDecoder<validate> {
DCHECK(stack_.empty());
DCHECK(control_.empty());
if (FLAG_wasm_code_fuzzer_gen_test) {
PrintRawWasmCode(this->start_, this->end_);
}
base::ElapsedTimer decode_timer;
if (FLAG_trace_wasm_decode_time) {
decode_timer.Start();
......
......@@ -879,7 +879,8 @@ std::pair<uint32_t, uint32_t> StackEffect(const WasmModule* module,
void PrintRawWasmCode(const byte* start, const byte* end) {
AccountingAllocator allocator;
PrintRawWasmCode(&allocator, FunctionBody{nullptr, 0, start, end}, nullptr);
PrintRawWasmCode(&allocator, FunctionBody{nullptr, 0, start, end}, nullptr,
kPrintLocals);
}
namespace {
......@@ -898,7 +899,8 @@ const char* RawOpcodeName(WasmOpcode opcode) {
} // namespace
bool PrintRawWasmCode(AccountingAllocator* allocator, const FunctionBody& body,
const wasm::WasmModule* module) {
const wasm::WasmModule* module,
PrintLocals print_locals) {
OFStream os(stdout);
Zone zone(allocator, ZONE_NAME);
WasmDecoder<Decoder::kNoValidate> decoder(module, body.sig, body.start,
......@@ -914,7 +916,7 @@ bool PrintRawWasmCode(AccountingAllocator* allocator, const FunctionBody& body,
// Print the local declarations.
BodyLocalDecls decls(&zone);
BytecodeIterator i(body.start, body.end, &decls);
if (body.start != i.pc() && !FLAG_wasm_code_fuzzer_gen_test) {
if (body.start != i.pc() && print_locals == kPrintLocals) {
os << "// locals: ";
if (!decls.type_list.empty()) {
ValueType type = decls.type_list[0];
......
......@@ -53,8 +53,10 @@ DecodeResult VerifyWasmCodeWithStats(AccountingAllocator* allocator,
DecodeResult BuildTFGraph(AccountingAllocator* allocator, TFBuilder* builder,
FunctionBody& body);
enum PrintLocals { kPrintLocals, kOmitLocals };
V8_EXPORT_PRIVATE
bool PrintRawWasmCode(AccountingAllocator* allocator, const FunctionBody& body,
const wasm::WasmModule* module);
const wasm::WasmModule* module, PrintLocals print_locals);
// A simplified form of AST printing, e.g. from a debugger.
void PrintRawWasmCode(const byte* start, const byte* end);
......
......@@ -89,29 +89,105 @@ 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"
<< " .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,23 +224,10 @@ 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);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment