Commit 0afe2524 authored by Clemens Hammacher's avatar Clemens Hammacher Committed by Commit Bot

[wasm] Add fuzzing for Liftoff

Each valid memory module generated by one of the wasm fuzzers will now
also be executed in Liftoff, and the result of the execution will be
compared against the interpreted result.

R=ahaas@chromium.org

Bug: v8:6600
Change-Id: I6a437faae4230ce4dfc7924dd1418da20ea92356
Reviewed-on: https://chromium-review.googlesource.com/753328Reviewed-by: 's avatarAndreas Haas <ahaas@chromium.org>
Commit-Queue: Clemens Hammacher <clemensh@chromium.org>
Cr-Commit-Position: refs/heads/master@{#49154}
parent 7621d487
......@@ -13,6 +13,7 @@
#include "src/wasm/wasm-module.h"
#include "src/zone/accounting-allocator.h"
#include "src/zone/zone.h"
#include "test/common/wasm/flag-utils.h"
#include "test/common/wasm/wasm-module-runner.h"
#include "test/fuzzer/fuzzer-support.h"
......@@ -147,8 +148,12 @@ int WasmExecutionFuzzer::FuzzWasmModule(
ErrorThrower interpreter_thrower(i_isolate, "Interpreter");
ModuleWireBytes wire_bytes(buffer.begin(), buffer.end());
MaybeHandle<WasmModuleObject> compiled_module =
SyncCompile(i_isolate, &interpreter_thrower, wire_bytes);
// Compile with Turbofan here. Liftoff will be tested later.
MaybeHandle<WasmModuleObject> compiled_module;
{
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();
......@@ -180,17 +185,19 @@ int WasmExecutionFuzzer::FuzzWasmModule(
if (!compiles) return 0;
int32_t result_interpreted;
int32_t result_interpreter;
bool possible_nondeterminism = false;
{
MaybeHandle<WasmInstanceObject> interpreter_instance = SyncInstantiate(
i_isolate, &interpreter_thrower, compiled_module.ToHandleChecked(),
MaybeHandle<JSReceiver>(), MaybeHandle<JSArrayBuffer>());
// Ignore instantiation failure.
if (interpreter_thrower.error()) {
return 0;
}
result_interpreted = testing::InterpretWasmModule(
result_interpreter = testing::InterpretWasmModule(
i_isolate, interpreter_instance.ToHandleChecked(), &interpreter_thrower,
0, interpreter_args.get(), &possible_nondeterminism);
}
......@@ -201,36 +208,66 @@ int WasmExecutionFuzzer::FuzzWasmModule(
return 0;
}
int32_t result_compiled;
bool expect_exception =
result_interpreter == static_cast<int32_t>(0xdeadbeef);
int32_t result_turbofan;
{
ErrorThrower compiler_thrower(i_isolate, "Compiler");
ErrorThrower compiler_thrower(i_isolate, "Turbofan");
MaybeHandle<WasmInstanceObject> compiled_instance = SyncInstantiate(
i_isolate, &compiler_thrower, compiled_module.ToHandleChecked(),
MaybeHandle<JSReceiver>(), MaybeHandle<JSArrayBuffer>());
DCHECK(!compiler_thrower.error());
result_compiled = testing::CallWasmFunctionForTesting(
result_turbofan = testing::CallWasmFunctionForTesting(
i_isolate, compiled_instance.ToHandleChecked(), &compiler_thrower,
"main", num_args, compiler_args.get());
}
// 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
// This sign bit may cause result_interpreter to be different than
// result_turbofan. 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 (!possible_nondeterminism) {
CHECK_EQ(expect_exception, i_isolate->has_pending_exception());
i_isolate->clear_pending_exception();
if (!expect_exception && result_interpreter != result_turbofan) {
uint32_t hash = StringHasher::HashSequentialString(
data, static_cast<int>(size), kWasmCodeFuzzerHashSeed);
V8_Fatal(__FILE__, __LINE__,
"interpreter != turbofan (%x vs %x); WasmCodeFuzzerHash=%x",
result_interpreter, result_turbofan, hash);
}
}
if (result_interpreted == bit_cast<int32_t>(0xdeadbeef)) {
CHECK(i_isolate->has_pending_exception());
int32_t result_liftoff;
{
FlagScope<bool> liftoff(&FLAG_liftoff, true);
ErrorThrower compiler_thrower(i_isolate, "Liftoff");
// Re-compile with Liftoff.
MaybeHandle<WasmInstanceObject> compiled_instance =
SyncCompileAndInstantiate(i_isolate, &compiler_thrower, wire_bytes,
MaybeHandle<JSReceiver>(),
MaybeHandle<JSArrayBuffer>());
DCHECK(!compiler_thrower.error());
result_liftoff = testing::CallWasmFunctionForTesting(
i_isolate, compiled_instance.ToHandleChecked(), &compiler_thrower,
"main", num_args, compiler_args.get());
}
if (!possible_nondeterminism) {
CHECK_EQ(expect_exception, i_isolate->has_pending_exception());
i_isolate->clear_pending_exception();
} else {
CHECK(!i_isolate->has_pending_exception());
if (result_interpreted != result_compiled) {
V8_Fatal(__FILE__, __LINE__, "WasmCodeFuzzerHash=%x",
StringHasher::HashSequentialString(data, static_cast<int>(size),
kWasmCodeFuzzerHashSeed));
if (!expect_exception && result_interpreter != result_liftoff) {
uint32_t hash = StringHasher::HashSequentialString(
data, static_cast<int>(size), kWasmCodeFuzzerHashSeed);
V8_Fatal(__FILE__, __LINE__,
"interpreter != liftoff (%x vs %x); WasmCodeFuzzerHash=%x",
result_interpreter, result_liftoff, hash);
}
}
return 0;
}
......
......@@ -2,8 +2,8 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef WASM_SECTION_FUZZERS_H_
#define WASM_SECTION_FUZZERS_H_
#ifndef WASM_FUZZER_COMMON_H_
#define WASM_FUZZER_COMMON_H_
#include <stddef.h>
#include <stdint.h>
......@@ -43,4 +43,4 @@ class WasmExecutionFuzzer {
} // namespace wasm
} // namespace internal
} // namespace v8
#endif // WASM_SECTION_FUZZERS_H_
#endif // WASM_FUZZER_COMMON_H_
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